Compare commits

..

112 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
8b0feb9022 fix(webapp): handle the too many requests error 2023-07-16 21:19:16 +02:00
Ahmed Bouhuolia
92f929152f feat(server): expose the api rate limit to the env vars 2023-07-16 21:15:13 +02:00
Ahmed Bouhuolia
da514403a1 chore: add recognition to README.md file 2023-07-07 02:34:00 +02:00
Ahmed Bouhuolia
d57f9e5171 chore: update README.md 2023-07-07 02:24:59 +02:00
Ahmed Bouhuolia
0a1299b8a6 Merge pull request #190 from bigcapitalhq/all-contributors/add-scheibling
docs: add scheibling as a contributor for bug
2023-07-07 02:21:52 +02:00
allcontributors[bot]
326a2038e7 docs: update .all-contributorsrc [skip ci] 2023-07-07 00:21:40 +00:00
allcontributors[bot]
94bb153120 docs: update README.md [skip ci] 2023-07-07 00:21:39 +00:00
Ahmed Bouhuolia
223756b7ae Update README.md 2023-07-07 02:20:47 +02:00
Ahmed Bouhuolia
a773ee9966 Merge pull request #189 from bigcapitalhq/all-contributors/add-ameir
docs: add ameir as a contributor for bug
2023-07-07 02:20:11 +02:00
Ahmed Bouhuolia
47790fba84 Merge branch 'develop' into all-contributors/add-ameir 2023-07-07 02:20:06 +02:00
Ahmed Bouhuolia
b122fdc43a Merge pull request #188 from bigcapitalhq/all-contributors/add-elforjani13
docs: add elforjani13 as a contributor for code
2023-07-07 02:18:56 +02:00
allcontributors[bot]
cb93f313ec docs: update .all-contributorsrc [skip ci] 2023-07-07 00:18:32 +00:00
allcontributors[bot]
74c31c5f20 docs: update README.md [skip ci] 2023-07-07 00:18:31 +00:00
allcontributors[bot]
d411ae3e68 docs: update .all-contributorsrc [skip ci] 2023-07-07 00:16:16 +00:00
allcontributors[bot]
aecef878ba docs: update README.md [skip ci] 2023-07-07 00:16:15 +00:00
Ahmed Bouhuolia
ec90056f7b Merge pull request #186 from bigcapitalhq/all-contributors/add-abouolia
docs: add abouolia as a contributor for code
2023-07-07 02:14:40 +02:00
Ahmed Bouhuolia
30f2f1fb4c Update README.md 2023-07-07 02:13:25 +02:00
Ahmed Bouhuolia
c72f5374f3 Update README.md 2023-07-07 02:13:13 +02:00
allcontributors[bot]
66de03b143 docs: create .all-contributorsrc [skip ci] 2023-07-07 00:07:19 +00:00
allcontributors[bot]
2b33583a03 docs: update README.md [skip ci] 2023-07-07 00:07:18 +00:00
Ahmed Bouhuolia
e5611b4446 Merge pull request #176 from bigcapitalhq/e2e-onboarding
feat(e2e): E2E onboarding process
2023-07-07 01:32:49 +02:00
Ahmed Bouhuolia
d12157a8d4 Merge branch 'develop' into e2e-onboarding 2023-07-07 01:26:58 +02:00
Ahmed Bouhuolia
b24badfa52 chore: add api rewrite to vercel configure 2023-07-07 01:14:37 +02:00
Ahmed Bouhuolia
c992562760 update CHANGELOG.md 2023-06-28 19:37:33 +02:00
Ahmed Bouhuolia
485138344c Merge pull request #182 from bigcapitalhq/abouhuolia/big-20-selecting-the-default-branch-for-opening-balance-branch-in
fix(webapp): no default branch for customer/vendor opening balance branch
2023-06-28 18:15:19 +02:00
Ahmed Bouhuolia
8d990ae85d fix(webapp): no default branch for customer/vendor opening balance branch 2023-06-28 18:07:47 +02:00
Ahmed Bouhuolia
7fbe51ddf2 Merge pull request #179 from bigcapitalhq/abouhuolia/big-29-no-currency-in-amount-field-on-money-inout-dialogs
fix(webapp): No currency in amount field on money in/out dialogs
2023-06-28 12:27:12 +02:00
Ahmed Bouhuolia
215eb97762 Merge branch 'develop' into abouhuolia/big-29-no-currency-in-amount-field-on-money-inout-dialogs 2023-06-28 12:23:06 +02:00
Ahmed Bouhuolia
3d4fd0b904 fix(webapp): transaction number duplicated variable name 2023-06-28 12:21:22 +02:00
Ahmed Bouhuolia
e552ff6449 Merge pull request #180 from bigcapitalhq/abouhuolia/big-40-storing-cash-flow-transaction-description
fix: Storing cash flow transaction description
2023-06-28 11:08:23 +02:00
Ahmed Bouhuolia
268942af42 Merge pull request #181 from bigcapitalhq/abouhuolia/big-39-the-statement-note-does-not-saving-in-payment-receive-and
fix: internal note of invoice/bill payment does not saving
2023-06-28 11:07:55 +02:00
Ahmed Bouhuolia
02489a907a fix(webapp): internal note of invoice/bill payment does not saving 2023-06-28 11:06:33 +02:00
Ahmed Bouhuolia
4e0037d1c0 fix(server): showing transaction statement on cash flow transactions details drawer 2023-06-28 01:00:27 +02:00
Ahmed Bouhuolia
39786e5b1f fix(server): storing cash flow transaction statement to GL entry note 2023-06-28 00:58:47 +02:00
Ahmed Bouhuolia
6373862044 fix(webapp): No currency in amount field on money in/out dialogs 2023-06-27 21:32:08 +02:00
Ahmed Bouhuolia
b46154ba59 feat(e2e): add default extra header to new e2e browser pages 2023-06-27 00:25:44 +02:00
Ahmed Bouhuolia
59e3a4016b Merge pull request #177 from bigcapitalhq/abouhuolia/big-38-payment-made-form-does-not-handle-not-unique-number-an-error
fix(webapp): payment made form does not handle not unique number an e…
2023-06-26 23:08:57 +02:00
Ahmed Bouhuolia
b6a1c9ab4b fix(webapp): payment made form does not handle not unique number an error message 2023-06-26 20:57:52 +02:00
Ahmed Bouhuolia
7171fb2a69 Merge branch 'develop' into e2e-onboarding 2023-06-23 16:12:03 +02:00
Ahmed Bouhuolia
c64a14aef3 Merge branch 'develop' into e2e-onboarding 2023-06-23 16:10:47 +02:00
Ahmed Bouhuolia
ac539aed34 chore: remove debug from playwright script 2023-06-23 16:10:29 +02:00
Ahmed Bouhuolia
c7b4846cb0 Merge pull request #171 from bigcapitalhq/abouhuolia/big-21-close-select-icon-clashes-with-caret-icon
feat(webapp): refactor customer and vendor select component
2023-06-23 16:06:55 +02:00
Ahmed Bouhuolia
d54aac9b32 Merge branch 'develop' into abouhuolia/big-21-close-select-icon-clashes-with-caret-icon 2023-06-23 16:05:21 +02:00
Ahmed Bouhuolia
fe87713df0 Merge pull request #172 from bigcapitalhq/abouhuolia/big-29-no-currency-in-amount-field-on-money-inout-dialogs
fix(webapp): should not show the form before loading account
2023-06-23 15:57:06 +02:00
Ahmed Bouhuolia
4770fdf709 Merge pull request #173 from bigcapitalhq/abouhuolia/big-37-item-drawer-floating
fix(webapp): style of quick item drawer
2023-06-23 15:55:58 +02:00
Ahmed Bouhuolia
1b3c525ba5 Merge pull request #170 from bigcapitalhq/split-components-in-seprate-files
chore(webapp): move auto-increment components in separate files
2023-06-23 15:55:22 +02:00
Ahmed Bouhuolia
b35d22d3b3 feat(e2e): onboarding process 2023-06-23 14:32:36 +02:00
Ahmed Bouhuolia
44fce6f33e feat(e2e): WIP e2e onboarding process 2023-06-23 02:45:30 +02:00
Ahmed Bouhuolia
e58a1d6ad1 chore(webapp): localization tweaks 2023-06-22 22:12:23 +02:00
Ahmed Bouhuolia
5f191cf335 fix(webapp): customer/vendor select should update deps 2023-06-22 22:07:39 +02:00
Ahmed Bouhuolia
46bf1cc39a fix(webapp): style of quick item drawer 2023-06-22 20:48:27 +02:00
Ahmed Bouhuolia
c98fe00f88 fix(webapp): should not show the form before loading account 2023-06-22 20:13:29 +02:00
Ahmed Bouhuolia
4b95c19d3e chore: update @blueprintjs-formik/select to the latest version 2023-06-22 19:54:54 +02:00
Ahmed Bouhuolia
eadaac30d6 feat(webapp): refactor customer and vendor select component 2023-06-22 17:26:33 +02:00
Ahmed Bouhuolia
ca4d543482 fix(webapp): quick create item drawer 2023-06-22 01:51:42 +02:00
Ahmed Bouhuolia
1f3adf4879 chore(webapp): move components in separate files 2023-06-22 01:30:05 +02:00
Ahmed Bouhuolia
532ad61500 Merge pull request #169 from bigcapitalhq/abouolia-patch-1
Rename writeInvoicesJEntries.ts to WriteInvoicesJEntries.ts
2023-06-19 23:03:25 +02:00
Ahmed Bouhuolia
a44d779670 Rename writeInvoicesJEntries.ts to WriteInvoicesJEntries.ts 2023-06-19 23:00:22 +02:00
Ahmed Bouhuolia
ab5f9f50d0 chore: update CHANGELOG file 2023-06-19 22:58:33 +02:00
Ahmed Bouhuolia
f3f10db6db chore: change the default BASE_URL env var value 2023-06-19 22:56:58 +02:00
Ahmed Bouhuolia
de5694681b Merge pull request #168 from bigcapitalhq/abouhuolia/big-30-create-a-new-warehouse-transfer-broken
fix(webapp): warehouses select component
2023-06-19 22:44:56 +02:00
Ahmed Bouhuolia
b1a997c287 fix(webapp): warehouses select component 2023-06-19 22:43:19 +02:00
Ahmed Bouhuolia
3e36146bce Merge pull request #167 from bigcapitalhq/abouhuolia/big-33-sending-emails-on-reset-password-and-registration
fix(server): sending emails on reset password and registration
2023-06-19 16:04:25 +02:00
Ahmed Bouhuolia
db833888c8 Merge pull request #160 from bigcapitalhq/abouhuolia/big-17-issue-in-manual-journal-placeholder-text
fix(webapp): manual journal placeholder text
2023-06-19 16:02:12 +02:00
Ahmed Bouhuolia
c415e3d693 Merge pull request #161 from bigcapitalhq/abouhuolia/big-32-sidebar
fix(webapp): rename sidebar localization keys names to be keyword path
2023-06-19 16:01:43 +02:00
Ahmed Bouhuolia
e145eabf02 Merge pull request #162 from bigcapitalhq/abouhuolia/big-22-make-the-remove-line-text-to-be-in-red
fix(webapp): change the remove line option text to be red to intent as danger action
2023-06-19 16:00:54 +02:00
Ahmed Bouhuolia
caab21647d Merge pull request #159 from bigcapitalhq/abouhuolia/big-24-adjustment-type-options-do-not-show-up-2
fix(webapp): adjustment type options do not show up
2023-06-19 16:00:20 +02:00
Ahmed Bouhuolia
98528e9e5b Merge pull request #158 from bigcapitalhq/abouhuolia/big-26-add-inventory-adjustment-option-to-the-item-drawer
feat(webapp): add Inventory Adjustment option to the item drawer
2023-06-19 15:59:11 +02:00
Ahmed Bouhuolia
b993fad37f fix(webapp): change the min password length of reset password 2023-06-19 15:55:20 +02:00
Ahmed Bouhuolia
94ea44b58e fix(server): change the reigster min password length 2023-06-19 15:55:06 +02:00
Ahmed Bouhuolia
877a57043a fix(server): sending emails on reset password and registration 2023-06-19 15:36:18 +02:00
Ahmed Bouhuolia
70415d1d63 fix(webapp): change the remove line option text to be red to intent as danger action 2023-06-15 20:49:23 +02:00
Ahmed Bouhuolia
ef2d1977d6 fix(webapp): rename sidebar localization keys names to be keyword path 2023-06-15 20:12:31 +02:00
Ahmed Bouhuolia
46ea26891d fix(webapp): manual journal placeholder text 2023-06-15 20:08:39 +02:00
Ahmed Bouhuolia
f750cede89 fix(webapp): adjustment type options do not show up 2023-06-15 20:00:34 +02:00
Ahmed Bouhuolia
e5d0f16096 feat(webapp): add Inventory Adjustment option to the item drawer 2023-06-15 19:49:23 +02:00
Ahmed Bouhuolia
706694c768 Merge pull request #157 from bigcapitalhq/abouhuolia/big-23-payment-made-details-drawer-does-not-show-up-3
fix(webapp): use all drawers names from common enum object
2023-06-14 21:53:55 +02:00
Ahmed Bouhuolia
d1a09e3b15 fix(webapp): use all drawers name from common enum object 2023-06-14 19:51:14 +02:00
Ahmed Bouhuolia
01c27b56ef Merge pull request #155 from bigcapitalhq/abouhuolia/big-19-delete-expense-transaction-does-not-work
fix(server): the expense transaction journal entries
2023-06-14 13:05:34 +02:00
Ahmed Bouhuolia
0d8fb8cf25 fix(server): the expense transaction journal entries 2023-06-14 13:00:26 +02:00
Ahmed Bouhuolia
6562e3ab8c chore: update CHANGELOG.md 2023-06-14 12:10:35 +02:00
Ahmed Bouhuolia
c93650ffd3 Merge pull request #139 from bigcapitalhq/change-onboarding-footer-links
chore(webapp): change the footer links of onboarding pages
2023-06-13 23:45:16 +02:00
Ahmed Bouhuolia
e6a2825065 chore(webapp): change the footer links of onboarding pages 2023-06-13 20:30:29 +02:00
Ahmed Bouhuolia
0c2a0b0010 Update README.md 2023-06-12 22:55:57 +02:00
Ahmed Bouhuolia
a332c51249 chore: change the default SIGNUP_DISABLED env variable 2023-06-12 21:15:27 +02:00
Ahmed Bouhuolia
0b6d0bc016 dump version 0.9.6 2023-06-12 19:43:36 +02:00
Ahmed Bouhuolia
e6336b1451 Merge pull request #136 from bigcapitalhq/add-monorepo-version-on-sidebar
feat(webapp): add monorepo version on the sidebar
2023-06-12 19:42:37 +02:00
Ahmed Bouhuolia
46290c4d37 Merge pull request #138 from bigcapitalhq/remove-duplicated-form-submitting
fix(webapp): remove duplicated form submitting
2023-06-12 18:55:18 +02:00
Ahmed Bouhuolia
ff2b7563c8 fix(webapp): remove duplicated form submitting 2023-06-12 18:47:28 +02:00
Ahmed Bouhuolia
b9572420ed feat(webapp): add monorepo version on the sidebar 2023-06-12 02:44:12 +02:00
Ahmed Bouhuolia
35ebb9c2aa Merge pull request #134 from bigcapitalhq/contacts-opening-balance-exchange-rate
fix(webapp): customer/vendor opening balance with exchange rate
2023-06-11 20:12:44 +02:00
Ahmed Bouhuolia
3ebeb29dc0 chore(webapp): vendor tabs 2023-06-11 20:12:26 +02:00
Ahmed Bouhuolia
8e98068538 fix(webapp): vendor form fastField of opening balance field 2023-06-11 20:11:30 +02:00
Ahmed Bouhuolia
6a72594faf fix(webapp): update condition of customer opening balance 2023-06-11 20:09:51 +02:00
Ahmed Bouhuolia
728729094a Merge branch 'develop' into contacts-opening-balance-exchange-rate 2023-06-11 19:56:54 +02:00
Ahmed Bouhuolia
93d540fbd2 fix(webapp): style tweaks on customer/vendor tabs 2023-06-11 19:53:15 +02:00
Ahmed Bouhuolia
eb9b6ce717 Merge pull request #133 from bigcapitalhq/add-duplicate-icon-to-list
fix(webapp): add duplicate icon to customers and vendors table
2023-06-11 19:36:52 +02:00
Ahmed Bouhuolia
f716d42d26 Merge pull request #135 from bigcapitalhq/fix-make-journal-with-different-accounts
fix(webapp): make journal error when create journal with accounts have different currency
2023-06-11 19:36:37 +02:00
Ahmed Bouhuolia
1c4c364f06 Merge pull request #132 from bigcapitalhq/filter-ledger-entries-ar-ap
fix(server): filter ledger entries that effect contact balance to AR/AP accounts only
2023-06-11 19:35:53 +02:00
Ahmed Bouhuolia
162ad91547 fix(webapp): handle make journal error when create journal with accounts have different currency 2023-06-11 19:34:24 +02:00
Ahmed Bouhuolia
2950e5ede4 fix(webapp): customer/vendor opening balnace with exchange rate 2023-06-11 19:29:26 +02:00
Ahmed Bouhuolia
73b041d8d2 fix(webapp): add deuplicate icon to customers and vendors table 2023-06-11 19:25:39 +02:00
Ahmed Bouhuolia
7bf008a9cb fix(server): filter ledger entries that effect contact balance to AR/AP accounts only 2023-06-11 19:23:31 +02:00
Ahmed Bouhuolia
4d9e3ccfb4 fix(server): disable webpack minification for class name reading 2023-06-08 22:38:43 +02:00
Ahmed Bouhuolia
1bfe19f26c fix: change the default charset value 2023-06-08 13:19:58 +02:00
Ahmed Bouhuolia
a371cedb67 Merge pull request #130 from bigcapitalhq/normalized
fix docker-compose line-ending issue on Windows
2023-06-06 20:40:42 +02:00
Ahmed Bouhuolia
4ed9c36ebd feat: set default value to env vars 2023-06-06 20:37:42 +02:00
ElforJani13
e24b23ce7e 🐛 FIX: 2023-06-06 19:49:25 +02:00
Ahmed Bouhuolia
19fe6e2423 fix: normalize nginx bash the line endings 2023-06-06 18:37:21 +02:00
Ahmed Bouhuolia
aec09f178b Merge pull request #128 from bigcapitalhq/BIG-435-migrate-to-maria-db-v-11
feat: migrate the server to MariaDB
2023-06-04 14:45:47 +02:00
Ahmed Bouhuolia
ffe51bae07 feat: migrate the server to MariaDB 2023-06-04 14:38:53 +02:00
Ahmed Bouhuolia
68231d5edb Merge pull request #125 from bigcapitalhq/docker-compose-env-variables
feat: add env variable to customize the proxy public ports
2023-05-31 20:30:44 +02:00
272 changed files with 3360 additions and 4390 deletions

53
.all-contributorsrc Normal file
View File

@@ -0,0 +1,53 @@
{
"files": [
"README.md"
],
"imageSize": 100,
"commit": false,
"commitType": "docs",
"commitConvention": "angular",
"contributors": [
{
"login": "abouolia",
"name": "Ahmed Bouhuolia",
"avatar_url": "https://avatars.githubusercontent.com/u/2197422?v=4",
"profile": "https://github.com/abouolia",
"contributions": [
"code"
]
},
{
"login": "ameir",
"name": "Ameir Abdeldayem",
"avatar_url": "https://avatars.githubusercontent.com/u/374330?v=4",
"profile": "http://ameir.net",
"contributions": [
"bug"
]
},
{
"login": "elforjani13",
"name": "ElforJani13",
"avatar_url": "https://avatars.githubusercontent.com/u/39470382?v=4",
"profile": "https://github.com/elforjani13",
"contributions": [
"code"
]
},
{
"login": "scheibling",
"name": "Lars Scheibling",
"avatar_url": "https://avatars.githubusercontent.com/u/24367830?v=4",
"profile": "https://scheibling.se",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,
"skipCi": true,
"repoType": "github",
"repoHost": "https://github.com",
"projectName": "bigcapital",
"projectOwner": "bigcapitalhq"
}

View File

@@ -8,26 +8,32 @@ MAIL_FROM_NAME=
MAIL_FROM_ADDRESS= MAIL_FROM_ADDRESS=
# Database # Database
DB_USER= DB_HOST=mysql
DB_HOST= DB_USER=bigcapital
DB_PASSWORD= DB_PASSWORD=bigcapital
DB_CHARSET= DB_ROOT_PASSWORD=root
DB_CHARSET=utf8
# System database # System database
SYSTEM_DB_NAME=bigcapital_system SYSTEM_DB_NAME=bigcapital_system
# SYSTEM_DB_USER=
# SYSTEM_DB_PASSWORD=
# SYSTEM_DB_NAME=
# SYSTEM_DB_CHARSET=
# Tenants databases # Tenant databases
TENANT_DB_NAME_PERFIX=bigcapital_tenant_ TENANT_DB_NAME_PERFIX=bigcapital_tenant_
# TENANT_DB_HOST=
# MongoDB # TENANT_DB_USER=
MONGODB_DATABASE_URL=mongodb://localhost/bigcapital # TENANT_DB_PASSWORD=
# TENANT_DB_CHARSET=
# Authentication
JWT_SECRET=b0JDZW56RnV6aEthb0RGPXVEcUI
# Application # Application
BASE_URL=https://bigcapital.ly BASE_URL=http://example.com
CONTACT_US_MAIL=support@bigcapital.ly JWT_SECRET=b0JDZW56RnV6aEthb0RGPXVEcUI
# Jobs MongoDB
MONGODB_DATABASE_URL=mongodb://localhost/bigcapital
# App proxy # App proxy
PUBLIC_PROXY_PORT=80 PUBLIC_PROXY_PORT=80
@@ -38,6 +44,9 @@ AGENDASH_AUTH_USER=agendash
AGENDASH_AUTH_PASSWORD=123123 AGENDASH_AUTH_PASSWORD=123123
# Sign-up restrictions # Sign-up restrictions
SIGNUP_DISABLED=true SIGNUP_DISABLED=false
SIGNUP_ALLOWED_DOMAINS= SIGNUP_ALLOWED_DOMAINS=
SIGNUP_ALLOWED_EMAILS= SIGNUP_ALLOWED_EMAILS=
# API rate limit (points,duration,block duration).
API_RATE_LIMIT=120,60,600

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
docker/nginx/scripts/build-nginx.sh text eol=lf
docker/mariadb/docker-entrypoint.sh text eol=lf

View File

@@ -2,6 +2,82 @@
All notable changes to Bigcapital server-side will be in this file. All notable changes to Bigcapital server-side will be in this file.
# [0.9.9] - 28-06-2023
* refactor: Customer and vendor select component by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/171
* chore: Move auto-increment components in separate files by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/170
* fix: Style of quick item drawer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/173
* fix: Should not show the form before loading account by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/172
* fix: Payment made form does not handle not unique number an e… by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/177
* fix: Internal note of invoice/bill payment does not saving by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/181
* fix: Storing cash flow transaction description by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/180
* fix: No currency in amount field on money in/out dialogs by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/179
* fix: No default branch for customer/vendor opening balance branch by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/182
# [0.9.8] - 19-06-2023
`bigcapitalhq/webapp`
* add: Inventory Adjustment option to the item drawer by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/158
* fix: use all drawers names from common enum object by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/157
* fix: adjustment type options do not show up by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/159
* fix: change the remove line text to be red to intent as a danger action by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/162
* fix: rename sidebar localization keys names to be keyword path by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/161
* fix: manual journal placeholder text by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/160
* fix: warehouses select component by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/168
`bigcapitalhq/server`
* fix: sending emails on reset password and registration by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/167
## [0.9.7] - 14-06-2023
`@bigcapital/webapp`
* fix: change the footer links of onboarding pages by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/139
`@bigcapital/server`
* fix: expense transaction journal entries by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/155
## [0.9.6] - 12-06-2023
`@bigcapital/webapp`
* fix: remove duplicated form submitting by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/138
* feat: add monorepo version on the application sidebar by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/136
## [0.9.5] - 11-06-2023
`@bigcapital/server`
* fix: filter ledger entries that effect contact balance to AR/AP accounts only by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/132
`@bigcapital/webapp`
* fix: catch journal error when create a journal with accounts have different currency by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/135
* fix: add duplicate icon to context menu of customers and vendors table by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/133
* fix: customer/vendor opening balance with exchange rate by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/134
## [0.9.4] - 08-06-2023
`@bigcapital/monorepo`
- fixed: docker-compose line-ending issue on Windows by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/130
`@bigcapital/server`
- fixed: Disable Webpack minification for JS class name reading.
## [0.9.3] -04-06-2023
`@bigcapital/monorepo`
* Added: Add env variable to customize the proxy public ports by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/125
* Added: Migrate the server database to MariaDB by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/128
## [0.9.2] - 31-05-2023
`@bigcapital/webapp`
- fixed: move `packaeg-lock.json` inside docker container.
- fixed: remove Sentry from the web client.
## [0.9.1] - 28-05-2023 ## [0.9.1] - 28-05-2023
`@bigcapital/server` `@bigcapital/server`

View File

@@ -7,6 +7,24 @@
<p align="center"> <p align="center">
Simple, smart online accounting software for small and medium businesses. Simple, smart online accounting software for small and medium businesses.
</p> </p>
<p align="center">
<a href="https://github.com/bigcapitalhq/bigcapital/commits/develop">
<img src="https://img.shields.io/github/commit-activity/m/bigcapitalhq/bigcapital/develop" />
</a>
<a href="https://discord.com/invite/c8nPBJafeb">
<img src="https://img.shields.io/discord/1066514716752625725?label=Discord" alt="" />
</a>
<a href="https://github.com/bigcapitalhq/bigcapital/graphs/contributors">
<img src="https://img.shields.io/github/contributors/bigcapitalhq/bigcapital" alt="" />
</a>
<a href="https://github.com/bigcapitalhq/bigcapital/blob/develop/LICENSE">
<img src="https://img.shields.io/github/license/bigcapitalhq/bigcapital" alt="" />
</a>
<a href="https://twitter.com/bigcapitalhq">
<img src="https://img.shields.io/twitter/follow/bigcapitalhq?style=social" alt="twitter" />
</a>
</p>
</p> </p>
# What's Bigcapital? # What's Bigcapital?
@@ -22,10 +40,45 @@ Bigcapital is a smart and open-source accounting and inventory software, Bigcapi
# Resources # Resources
- [Documentation](https://docs.bigcapital.ly/) - Learn how to use. - [Documentation](https://docs.bigcapital.ly/) - Learn how to use.
- [Contribution](https://github.com/bigcapitalhq/bigcapital/blob/develop/CONTRIBUTING.md) - Welcome to any contributions.
- [Discord](https://discord.com/invite/c8nPBJafeb) - Ask for help. - [Discord](https://discord.com/invite/c8nPBJafeb) - Ask for help.
- [Bug Tracker](https://github.com/bigcapitalhq/bigcapital/issues) - Notify us new bugs. - [Bug Tracker](https://github.com/bigcapitalhq/bigcapital/issues) - Notify us new bugs.
- [Source Code](https://github.com/bigcapitalhq/bigcapital) - Github repo.
# Changelog # Changelog
Please see [Releases](https://github.com/bigcapitalhq/bigcapital/releases) for more information what has changed recently. Please see [Releases](https://github.com/bigcapitalhq/bigcapital/releases) for more information what has changed recently.
# Recognition
<a href="https://news.ycombinator.com/item?id=36118990">
<img
style="width: 250px; height: 54px;" width="250" height="54"
alt="Featured on Hacker News"
src="https://hackernews-badge.vercel.app/api?id=36118990"
/>
</a>
# Contributors
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/abouolia"><img src="https://avatars.githubusercontent.com/u/2197422?v=4?s=100" width="100px;" alt="Ahmed Bouhuolia"/><br /><sub><b>Ahmed Bouhuolia</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=abouolia" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elforjani13"><img src="https://avatars.githubusercontent.com/u/39470382?v=4?s=100" width="100px;" alt="ElforJani13"/><br /><sub><b>ElforJani13</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/commits?author=elforjani13" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://ameir.net"><img src="https://avatars.githubusercontent.com/u/374330?v=4?s=100" width="100px;" alt="Ameir Abdeldayem"/><br /><sub><b>Ameir Abdeldayem</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Aameir" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://scheibling.se"><img src="https://avatars.githubusercontent.com/u/24367830?v=4?s=100" width="100px;" alt="Lars Scheibling"/><br /><sub><b>Lars Scheibling</b></sub></a><br /><a href="https://github.com/bigcapitalhq/bigcapital/issues?q=author%3Ascheibling" title="Bug reports">🐛</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!

View File

@@ -94,12 +94,12 @@ services:
mysql: mysql:
container_name: bigcapital-mysql container_name: bigcapital-mysql
build: build:
context: ./docker/mysql context: ./docker/mariadb
environment: environment:
- MYSQL_DATABASE=${SYSTEM_DB_NAME} - MYSQL_DATABASE=${SYSTEM_DB_NAME}
- MYSQL_USER=${DB_USER} - MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASSWORD} - MYSQL_PASSWORD=${DB_PASSWORD}
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD} - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
volumes: volumes:
- mysql:/var/lib/mysql - mysql:/var/lib/mysql
expose: expose:

View File

@@ -6,14 +6,14 @@
version: '3.3' version: '3.3'
services: services:
mysql: mariadb:
build: build:
context: ./docker/mysql context: ./docker/mariadb
environment: environment:
- MYSQL_DATABASE=${SYSTEM_DB_NAME} - MYSQL_DATABASE=${SYSTEM_DB_NAME}
- MYSQL_USER=${DB_USER} - MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASSWORD} - MYSQL_PASSWORD=${DB_PASSWORD}
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD} - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
volumes: volumes:
- mysql:/var/lib/mysql - mysql:/var/lib/mysql
expose: expose:

View File

@@ -1,4 +1,4 @@
FROM mysql:5.7 FROM mariadb:10.2
USER root USER root
ADD my.cnf /etc/mysql/conf.d/my.cnf ADD my.cnf /etc/mysql/conf.d/my.cnf
@@ -17,7 +17,7 @@ ENV MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
COPY ./init.sql /scripts/init.template.sql COPY ./init.sql /scripts/init.template.sql
COPY ./docker-entrypoint.sh /docker-entrypoint-initdb.d/docker-initialize.sh COPY ./docker-entrypoint.sh /docker-entrypoint-initdb.d/docker-initialize.sh
# The scripts in the docker-entrypoint-initdb.d/ directory are executed as # The scripts in the `docker-entrypoint-initdb.d/` directory are executed as
# the mysql user inside the MySQL Docker container. # the mysql user inside the MySQL Docker container.
RUN chown -R mysql:root /docker-entrypoint-initdb.d RUN chown -R mysql:root /docker-entrypoint-initdb.d
RUN chown -R mysql:root /scripts RUN chown -R mysql:root /scripts

View File

@@ -1,2 +1,3 @@
GRANT ALL PRIVILEGES ON *.* TO '{MYSQL_USER}'@'%' IDENTIFIED BY '{MYSQL_PASSWORD}' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO '{MYSQL_USER}'@'%' IDENTIFIED BY '{MYSQL_PASSWORD}' WITH GRANT OPTION;
FLUSH PRIVILEGES; FLUSH PRIVILEGES;

13
e2e/_utils.ts Normal file
View File

@@ -0,0 +1,13 @@
import { Page } from '@playwright/test';
export const clearLocalStorage = (page: Page) => {
return page.evaluate(`window.localStorage.clear()`);
};
export const defaultPageConfig = () => {
return {
extraHTTPHeaders: {
'ngrok-skip-browser-warning': 'any-value',
},
};
};

View File

@@ -1,14 +1,23 @@
import { test, expect, Page } from '@playwright/test'; import { test, expect, Page } from '@playwright/test';
import { faker } from '@faker-js/faker';
import { clearLocalStorage, defaultPageConfig } from './_utils';
let authPage: Page; let authPage: Page;
test.describe('authentication', () => { test.describe('authentication', () => {
test.beforeAll(async ({ browser }) => { test.beforeAll(async ({ browser }) => {
authPage = await browser.newPage(); authPage = await browser.newPage({ ...defaultPageConfig() });
});
test.afterAll(async () => {
await authPage.close();
});
test.afterEach(async ({ context }) => {
context.clearCookies();
await clearLocalStorage(authPage);
}); });
test.describe('login', () => { test.describe('login', () => {
test.beforeAll(async () => { test.beforeEach(async () => {
await authPage.goto('/auth/login'); await authPage.goto('/auth/login');
}); });
test('should show the login page.', async () => { test('should show the login page.', async () => {
@@ -30,10 +39,23 @@ test.describe('authentication', () => {
await authPage.getByRole('link', { name: 'Sign up' }).click(); await authPage.getByRole('link', { name: 'Sign up' }).click();
await expect(authPage.url()).toContain('/auth/register'); await expect(authPage.url()).toContain('/auth/register');
}); });
test('should the email or password is not correct.', async () => {
await authPage.getByLabel('Email Address').click();
await authPage.getByLabel('Email Address').fill(faker.internet.email());
await authPage.getByLabel('Password').click();
await authPage.getByLabel('Password').fill(faker.internet.password());
await authPage.getByRole('button', { name: 'Log in' }).click();
await expect(authPage.locator('body')).toContainText(
'The email and password you entered did not match our records.'
);
});
}); });
test.describe('register', () => { test.describe('register', () => {
test.beforeAll(async () => { test.beforeEach(async () => {
await authPage.goto('/auth/register'); await authPage.goto('/auth/register');
}); });
test('should first name, last name, email and password be required.', async () => { test('should first name, last name, email and password be required.', async () => {
@@ -52,10 +74,36 @@ test.describe('authentication', () => {
'Password is a required field' 'Password is a required field'
); );
}); });
test('should signup successfully.', async () => {
const form = authPage.locator('form');
await form.getByLabel('First Name').click();
await form.getByLabel('First Name').fill(faker.person.firstName());
await form.getByLabel('Email').click();
await form.getByLabel('Email').fill(faker.internet.email());
await form.getByLabel('Last Name').click();
await form.getByLabel('Last Name').fill(faker.person.lastName());
await form.getByLabel('Password').click();
await form.getByLabel('Password').fill(faker.internet.password());
await authPage.getByRole('button', { name: 'Register' }).click();
await expect(authPage.locator('h1')).toContainText(
'Register a New Organization now!'
);
});
}); });
test.describe('reset password', () => { test.describe('reset password', () => {
test.beforeAll(async () => { test.beforeAll(async ({ browser }) => {
authPage = await browser.newPage({ ...defaultPageConfig() });
});
test.afterAll(async () => {
await authPage.close();
});
test.beforeEach(async () => {
await authPage.goto('/auth/send_reset_password'); await authPage.goto('/auth/send_reset_password');
}); });
test('should email be required.', async () => { test('should email be required.', async () => {

86
e2e/onboarding.spec.ts Normal file
View File

@@ -0,0 +1,86 @@
import { test, expect, Page } from '@playwright/test';
import { faker } from '@faker-js/faker';
import { defaultPageConfig } from './_utils';
let authPage: Page;
let businessLegalName: string = faker.company.name();
test.describe('onboarding', () => {
test.beforeAll(async ({ browser }) => {
authPage = await browser.newPage({ ...defaultPageConfig() });
await authPage.goto('/auth/register');
const form = authPage.locator('form');
await form.getByLabel('First Name').fill(faker.person.firstName());
await form.getByLabel('Email').fill(faker.internet.email());
await form.getByLabel('Last Name').fill(faker.person.lastName());
await form.getByLabel('Password').fill(faker.internet.password());
await authPage.getByRole('button', { name: 'Register' }).click();
});
test('should validation catch all required fields', async () => {
const form = authPage.locator('form');
await authPage.getByRole('button', { name: 'Save & Continue' }).click();
await expect(form).toContainText('Organization name is a required field');
await expect(form).toContainText('Location is a required field');
await expect(form).toContainText('Base currency is a required field');
await expect(form).toContainText('Fiscal year is a required field');
await expect(form).toContainText('Time zone is a required field');
});
test.describe('after onboarding', () => {
test.beforeAll(async () => {
await authPage.getByLabel('Legal Organization Name').click();
await authPage
.getByLabel('Legal Organization Name')
.fill(businessLegalName);
// Fill Business Location.
await authPage
.getByRole('button', { name: 'Select Business Location...' })
.click();
await authPage.locator('a').filter({ hasText: 'Albania' }).click();
// Fill Base Currency.
await authPage
.getByRole('button', { name: 'Select Base Currency...' })
.click();
await authPage
.locator('a')
.filter({ hasText: 'AED - United Arab Emirates Dirham' })
.click();
// Fill Fasical Year.
await authPage
.getByRole('button', { name: 'Select Fiscal Year...' })
.click();
await authPage.locator('a').filter({ hasText: 'June - May' }).click();
// Fill Timezone.
await authPage
.getByRole('button', { name: 'Select Time Zone...' })
.click();
await authPage.getByText('Pacific/Marquesas-09:30').click();
// Click on Submit button
await authPage.getByRole('button', { name: 'Save & Continue' }).click();
});
test('should onboarding process success', async () => {
await expect(authPage.locator('body')).toContainText(
'Congrats! You are ready to go',
{
timeout: 30000,
}
);
});
test('should go to the dashboard after clicking on "Go to dashboard" button.', async () => {
await authPage.getByRole('button', { name: 'Go to dashboard' }).click();
await expect(
authPage.locator('[data-testId="dashboard-topbar"] h1')
).toContainText(businessLegalName);
});
});
});

View File

@@ -1,6 +1,6 @@
{ {
"$schema": "node_modules/lerna/schemas/lerna-schema.json", "$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": true, "useWorkspaces": true,
"version": "0.0.0", "version": "0.9.6",
"npmClient": "npm" "npmClient": "npm"
} }

14
package-lock.json generated
View File

@@ -333,6 +333,12 @@
"@jridgewell/trace-mapping": "0.3.9" "@jridgewell/trace-mapping": "0.3.9"
} }
}, },
"@faker-js/faker": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.0.2.tgz",
"integrity": "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==",
"dev": true
},
"@gar/promisify": { "@gar/promisify": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@@ -945,6 +951,7 @@
"version": "1.32.3", "version": "1.32.3",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.3.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.3.tgz",
"integrity": "sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==", "integrity": "sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==",
"dev": true,
"requires": { "requires": {
"@types/node": "*", "@types/node": "*",
"fsevents": "2.3.2", "fsevents": "2.3.2",
@@ -954,7 +961,8 @@
"playwright-core": { "playwright-core": {
"version": "1.32.3", "version": "1.32.3",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.3.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.3.tgz",
"integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==" "integrity": "sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==",
"dev": true
} }
} }
}, },
@@ -1003,7 +1011,8 @@
"@types/node": { "@types/node": {
"version": "18.14.6", "version": "18.14.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==",
"dev": true
}, },
"@types/normalize-package-data": { "@types/normalize-package-data": {
"version": "2.4.1", "version": "2.4.1",
@@ -2324,6 +2333,7 @@
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true "optional": true
}, },
"function-bind": { "function-bind": {

View File

@@ -18,12 +18,13 @@
"shared/*" "shared/*"
], ],
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^17.4.2",
"@commitlint/config-conventional": "^17.4.2", "@commitlint/config-conventional": "^17.4.2",
"@commitlint/config-lerna-scopes": "^17.4.2", "@commitlint/config-lerna-scopes": "^17.4.2",
"@faker-js/faker": "^8.0.2",
"@playwright/test": "^1.32.3",
"husky": "^8.0.3", "husky": "^8.0.3",
"lerna": "^6.4.1", "lerna": "^6.4.1"
"@commitlint/cli": "^17.4.2",
"@playwright/test": "^1.32.3"
}, },
"engines": { "engines": {
"node": "14.x" "node": "14.x"

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bigcapital/server", "name": "@bigcapital/server",
"version": "1.7.1", "version": "0.9.5",
"description": "", "description": "",
"main": "src/server.ts", "main": "src/server.ts",
"scripts": { "scripts": {

View File

@@ -65,6 +65,9 @@ exports.getCommonWebpackOptions = ({
}, },
], ],
}, },
optimization: {
minimize: false,
},
}; };
if (isDev) { if (isDev) {

View File

@@ -92,6 +92,7 @@ export default class AuthenticationController extends BaseController {
check('password') check('password')
.exists() .exists()
.isString() .isString()
.isLength({ min: 6 })
.trim() .trim()
.escape() .escape()
.isLength({ max: DATATYPES_LENGTH.STRING }), .isLength({ max: DATATYPES_LENGTH.STRING }),
@@ -106,7 +107,7 @@ export default class AuthenticationController extends BaseController {
return [ return [
check('password') check('password')
.exists() .exists()
.isLength({ min: 5 }) .isLength({ min: 6 })
.custom((value, { req }) => { .custom((value, { req }) => {
if (value !== req.body.confirm_password) { if (value !== req.body.confirm_password) {
throw new Error("Passwords don't match"); throw new Error("Passwords don't match");

View File

@@ -1,9 +1,12 @@
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import path from 'path'; import path from 'path';
import { toInteger } from 'lodash';
import { castCommaListEnvVarToArray, parseBoolean } from '@/utils'; import { castCommaListEnvVarToArray, parseBoolean } from '@/utils';
dotenv.config(); dotenv.config();
const API_RATE_LIMIT = process.env.API_RATE_LIMIT?.split(',') || [];
module.exports = { module.exports = {
/** /**
* Your favorite port * Your favorite port
@@ -95,16 +98,15 @@ module.exports = {
* JWT secret. * JWT secret.
*/ */
jwtSecret: process.env.JWT_SECRET, jwtSecret: process.env.JWT_SECRET,
resetPasswordSeconds: 600,
/** /**
* *
*/ */
customerSuccess: { resetPasswordSeconds: 600,
email: 'success@bigcapital.ly',
phoneNumber: '(218) 92 791 8381',
},
/**
* Application base URL.
*/
baseURL: process.env.BASE_URL, baseURL: process.env.BASE_URL,
/** /**
@@ -131,19 +133,9 @@ module.exports = {
blockDuration: 60 * 15, blockDuration: 60 * 15,
}, },
requests: { requests: {
points: 60, points: API_RATE_LIMIT[0] ? toInteger(API_RATE_LIMIT[0]) : 120,
duration: 60, duration: API_RATE_LIMIT[1] ? toInteger(API_RATE_LIMIT[1]) : 60,
blockDuration: 60 * 10, blockDuration: API_RATE_LIMIT[2] ? toInteger(API_RATE_LIMIT[2]) : 60 * 10,
},
},
/**
* Users registeration configuration.
*/
registration: {
countries: {
whitelist: ['LY'],
blacklist: [],
}, },
}, },
@@ -167,8 +159,6 @@ module.exports = {
browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT, browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT,
}, },
protocol: '',
hostname: '',
scheduleComputeItemCost: 'in 5 seconds', scheduleComputeItemCost: 'in 5 seconds',
/** /**

View File

@@ -4,6 +4,8 @@ export interface ILedger {
getEntries(): ILedgerEntry[]; getEntries(): ILedgerEntry[];
filter(cb: (entry: ILedgerEntry) => boolean): ILedger;
whereAccountId(accountId: number): ILedger; whereAccountId(accountId: number): ILedger;
whereContactId(contactId: number): ILedger; whereContactId(contactId: number): ILedger;
whereFromDate(fromDate: Date | string): ILedger; whereFromDate(fromDate: Date | string): ILedger;
@@ -39,6 +41,8 @@ export interface ILedgerEntry {
index: number; index: number;
indexGroup?: number; indexGroup?: number;
note?: string;
userId?: number; userId?: number;
itemId?: number; itemId?: number;
branchId?: number; branchId?: number;

View File

@@ -1,7 +1,7 @@
import { Container, Inject } from 'typedi'; import { Container } from 'typedi';
import AuthenticationService from '@/services/Authentication/AuthApplication'; import AuthenticationMailMesssages from '@/services/Authentication/AuthenticationMailMessages';
export default class WelcomeEmailJob { export default class ResetPasswordEmailJob {
/** /**
* Constructor method. * Constructor method.
* @param {Agenda} agenda * @param {Agenda} agenda
@@ -10,7 +10,7 @@ export default class WelcomeEmailJob {
agenda.define( agenda.define(
'reset-password-mail', 'reset-password-mail',
{ priority: 'high' }, { priority: 'high' },
this.handler.bind(this), this.handler.bind(this)
); );
} }
@@ -22,17 +22,13 @@ export default class WelcomeEmailJob {
public async handler(job, done: Function): Promise<void> { public async handler(job, done: Function): Promise<void> {
const { data } = job.attrs; const { data } = job.attrs;
const { user, token } = data; const { user, token } = data;
const Logger = Container.get('logger'); const authService = Container.get(AuthenticationMailMesssages);
const authService = Container.get(AuthenticationService);
Logger.info(`[send_reset_password] started.`, { data });
try { try {
await authService.mailMessages.sendResetPasswordMessage(user, token); await authService.sendResetPasswordMessage(user, token);
Logger.info(`[send_reset_password] finished.`, { data }); done();
done()
} catch (error) { } catch (error) {
Logger.error(`[send_reset_password] error.`, { data, error }); console.log(error);
done(error); done(error);
} }
} }

View File

@@ -1,22 +0,0 @@
import { Container } from 'typedi';
export default class SmsNotification {
constructor(agenda) {
agenda.define('sms-notification', { priority: 'high' }, this.handler);
}
/**
*
* @param {Job}job
*/
async handler(job) {
const { message, to } = job.attrs.data;
const smsClient = Container.get('SMSClient');
try {
await smsClient.sendMessage(to, message);
} catch (error) {
done(e);
}
}
}

View File

@@ -1,35 +0,0 @@
import { Container, Inject } from 'typedi';
import AuthenticationService from '@/services/Authentication/AuthApplication';
export default class WelcomeSMSJob {
/**
* Constructor method.
* @param {Agenda} agenda
*/
constructor(agenda) {
agenda.define('welcome-sms', { priority: 'high' }, this.handler);
}
/**
* Handle send welcome mail job.
* @param {Job} job
* @param {Function} done
*/
public async handler(job, done: Function): Promise<void> {
const { tenant, user } = job.attrs.data;
const Logger = Container.get('logger');
const authService = Container.get(AuthenticationService);
Logger.info(`[welcome_sms] started: ${job.attrs.data}`);
try {
await authService.smsMessages.sendWelcomeMessage(tenant, user);
Logger.info(`[welcome_sms] finished`, { tenant, user });
done();
} catch (error) {
Logger.info(`[welcome_sms] error`, { error, tenant, user });
done(error);
}
}
}

View File

@@ -1,39 +0,0 @@
import { Container } from 'typedi';
import AuthenticationService from '@/services/Authentication/AuthApplication';
export default class WelcomeEmailJob {
/**
* Constructor method.
* @param {Agenda} agenda -
*/
constructor(agenda) {
// Welcome mail and SMS message.
agenda.define(
'welcome-email',
{ priority: 'high' },
this.handler.bind(this),
);
}
/**
* Handle send welcome mail job.
* @param {Job} job
* @param {Function} done
*/
public async handler(job, done: Function): Promise<void> {
const { organizationId, user } = job.attrs.data;
const Logger: any = Container.get('logger');
const authService = Container.get(AuthenticationService);
Logger.info(`[welcome_mail] started: ${job.attrs.data}`);
try {
await authService.mailMessages.sendWelcomeMessage(user, organizationId);
Logger.info(`[welcome_mail] finished: ${job.attrs.data}`);
done();
} catch (error) {
Logger.error(`[welcome_mail] error: ${job.attrs.data}, error: ${error}`);
done(error);
}
}
}

View File

@@ -31,7 +31,6 @@ import OrgBuildSmsNotificationSubscriber from '@/subscribers/Organization/BuildS
import PurgeUserAbilityCache from '@/services/Users/PurgeUserAbilityCache'; import PurgeUserAbilityCache from '@/services/Users/PurgeUserAbilityCache';
import ResetLoginThrottleSubscriber from '@/subscribers/Authentication/ResetLoginThrottle'; import ResetLoginThrottleSubscriber from '@/subscribers/Authentication/ResetLoginThrottle';
import AuthenticationSubscriber from '@/subscribers/Authentication/SendResetPasswordMail'; import AuthenticationSubscriber from '@/subscribers/Authentication/SendResetPasswordMail';
import AuthSendWelcomeMailSubscriber from '@/subscribers/Authentication/SendWelcomeMail';
import PurgeAuthorizedUserOnceRoleMutate from '@/services/Roles/PurgeAuthorizedUser'; import PurgeAuthorizedUserOnceRoleMutate from '@/services/Roles/PurgeAuthorizedUser';
import SendSmsNotificationToCustomer from '@/subscribers/SaleInvoices/SendSmsNotificationToCustomer'; import SendSmsNotificationToCustomer from '@/subscribers/SaleInvoices/SendSmsNotificationToCustomer';
import SendSmsNotificationSaleReceipt from '@/subscribers/SaleReceipt/SendSmsNotificationToCustomer'; import SendSmsNotificationSaleReceipt from '@/subscribers/SaleReceipt/SendSmsNotificationToCustomer';
@@ -120,7 +119,6 @@ export const susbcribers = () => {
PurgeUserAbilityCache, PurgeUserAbilityCache,
ResetLoginThrottleSubscriber, ResetLoginThrottleSubscriber,
AuthenticationSubscriber, AuthenticationSubscriber,
AuthSendWelcomeMailSubscriber,
PurgeAuthorizedUserOnceRoleMutate, PurgeAuthorizedUserOnceRoleMutate,
SendSmsNotificationToCustomer, SendSmsNotificationToCustomer,
SendSmsNotificationSaleReceipt, SendSmsNotificationSaleReceipt,

View File

@@ -1,24 +1,18 @@
import Agenda from 'agenda'; import Agenda from 'agenda';
import WelcomeEmailJob from 'jobs/welcomeEmail';
import WelcomeSMSJob from 'jobs/WelcomeSMS';
import ResetPasswordMailJob from 'jobs/ResetPasswordMail'; import ResetPasswordMailJob from 'jobs/ResetPasswordMail';
import ComputeItemCost from 'jobs/ComputeItemCost'; import ComputeItemCost from 'jobs/ComputeItemCost';
import RewriteInvoicesJournalEntries from 'jobs/writeInvoicesJEntries'; import RewriteInvoicesJournalEntries from 'jobs/WriteInvoicesJEntries';
import UserInviteMailJob from 'jobs/UserInviteMail'; import UserInviteMailJob from 'jobs/UserInviteMail';
import OrganizationSetupJob from 'jobs/OrganizationSetup'; import OrganizationSetupJob from 'jobs/OrganizationSetup';
import OrganizationUpgrade from 'jobs/OrganizationUpgrade'; import OrganizationUpgrade from 'jobs/OrganizationUpgrade';
import SmsNotification from 'jobs/SmsNotification';
export default ({ agenda }: { agenda: Agenda }) => { export default ({ agenda }: { agenda: Agenda }) => {
new WelcomeEmailJob(agenda);
new ResetPasswordMailJob(agenda); new ResetPasswordMailJob(agenda);
new WelcomeSMSJob(agenda);
new UserInviteMailJob(agenda); new UserInviteMailJob(agenda);
new ComputeItemCost(agenda); new ComputeItemCost(agenda);
new RewriteInvoicesJournalEntries(agenda); new RewriteInvoicesJournalEntries(agenda);
new OrganizationSetupJob(agenda); new OrganizationSetupJob(agenda);
new OrganizationUpgrade(agenda); new OrganizationUpgrade(agenda);
new SmsNotification(agenda);
agenda.start(); agenda.start();
}; };

View File

@@ -1,9 +1,14 @@
import { Service, Inject } from 'typedi'; import { Service, Inject } from 'typedi';
import async from 'async'; import async from 'async';
import { Knex } from 'knex'; import { Knex } from 'knex';
import { ILedger, ISaleContactsBalanceQueuePayload } from '@/interfaces'; import {
ILedger,
ILedgerEntry,
ISaleContactsBalanceQueuePayload,
} from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService'; import HasTenancyService from '@/services/Tenancy/TenancyService';
import { TenantMetadata } from '@/system/models'; import { TenantMetadata } from '@/system/models';
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
@Service() @Service()
export class LedgerContactsBalanceStorage { export class LedgerContactsBalanceStorage {
@@ -49,6 +54,29 @@ export class LedgerContactsBalanceStorage {
await this.saveContactBalance(tenantId, ledger, contactId, trx); await this.saveContactBalance(tenantId, ledger, contactId, trx);
}; };
/**
* Filters AP/AR ledger entries.
* @param {number} tenantId
* @param {Knex.Transaction} trx
* @returns {Promise<(entry: ILedgerEntry) => boolean>}
*/
private filterARAPLedgerEntris = async (
tenantId: number,
trx?: Knex.Transaction
): Promise<(entry: ILedgerEntry) => boolean> => {
const { Account } = this.tenancy.models(tenantId);
const ARAPAcounts = await Account.query(trx).whereIn('accountType', [
ACCOUNT_TYPE.ACCOUNTS_RECEIVABLE,
ACCOUNT_TYPE.ACCOUNTS_PAYABLE,
]);
const ARAPAcountsIds = ARAPAcounts.map((a) => a.id);
return (entry: ILedgerEntry) => {
return ARAPAcountsIds.indexOf(entry.accountId) !== -1;
};
};
/** /**
* *
* @param {number} tenantId * @param {number} tenantId
@@ -63,7 +91,7 @@ export class LedgerContactsBalanceStorage {
trx?: Knex.Transaction trx?: Knex.Transaction
): Promise<void> => { ): Promise<void> => {
const { Contact } = this.tenancy.models(tenantId); const { Contact } = this.tenancy.models(tenantId);
const contact = await Contact.query().findById(contactId); const contact = await Contact.query(trx).findById(contactId);
// Retrieves the given tenant metadata. // Retrieves the given tenant metadata.
const tenantMeta = await TenantMetadata.query().findOne({ tenantId }); const tenantMeta = await TenantMetadata.query().findOne({ tenantId });
@@ -72,7 +100,15 @@ export class LedgerContactsBalanceStorage {
const isForeignContact = contact.currencyCode !== tenantMeta.baseCurrency; const isForeignContact = contact.currencyCode !== tenantMeta.baseCurrency;
// Filters the ledger base on the given contact id. // Filters the ledger base on the given contact id.
const contactLedger = ledger.whereContactId(contactId); const filterARAPLedgerEntris = await this.filterARAPLedgerEntris(
tenantId,
trx
);
const contactLedger = ledger
// Filter entries only that have contact id.
.whereContactId(contactId)
// Filter entries on AR/AP accounts.
.filter(filterARAPLedgerEntris);
const closingBalance = isForeignContact const closingBalance = isForeignContact
? contactLedger ? contactLedger

View File

@@ -21,6 +21,8 @@ export const transformLedgerEntryToTransaction = (
transactionNumber: entry.transactionNumber, transactionNumber: entry.transactionNumber,
referenceNumber: entry.referenceNumber, referenceNumber: entry.referenceNumber,
note: entry.note,
index: entry.index, index: entry.index,
indexGroup: entry.indexGroup, indexGroup: entry.indexGroup,

View File

@@ -5,59 +5,24 @@ import Mail from '@/lib/Mail';
@Service() @Service()
export default class AuthenticationMailMesssages { export default class AuthenticationMailMesssages {
/**
* Sends welcome message.
* @param {ISystemUser} user - The system user.
* @param {string} organizationName -
* @return {Promise<void>}
*/
async sendWelcomeMessage(
user: ISystemUser,
organizationId: string
): Promise<void> {
const root = __dirname + '/../../../views/images/bigcapital.png';
const mail = new Mail()
.setView('mail/Welcome.html')
.setSubject('Welcome to Bigcapital')
.setTo(user.email)
.setAttachments([
{
filename: 'bigcapital.png',
path: root,
cid: 'bigcapital_logo',
},
])
.setData({
firstName: user.firstName,
organizationId,
successPhoneNumber: config.customerSuccess.phoneNumber,
successEmail: config.customerSuccess.email,
});
await mail.send();
}
/** /**
* Sends reset password message. * Sends reset password message.
* @param {ISystemUser} user - The system user. * @param {ISystemUser} user - The system user.
* @param {string} token - Reset password token. * @param {string} token - Reset password token.
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async sendResetPasswordMessage( public async sendResetPasswordMessage(
user: ISystemUser, user: ISystemUser,
token: string token: string
): Promise<void> { ): Promise<void> {
const root = __dirname + '/../../../views/images/bigcapital.png'; await new Mail()
const mail = new Mail()
.setSubject('Bigcapital - Password Reset') .setSubject('Bigcapital - Password Reset')
.setView('mail/ResetPassword.html') .setView('mail/ResetPassword.html')
.setTo(user.email) .setTo(user.email)
.setAttachments([ .setAttachments([
{ {
filename: 'bigcapital.png', filename: 'bigcapital.png',
path: root, path: `${global.__views_dir}/images/bigcapital.png`,
cid: 'bigcapital_logo', cid: 'bigcapital_logo',
}, },
]) ])
@@ -65,9 +30,7 @@ export default class AuthenticationMailMesssages {
resetPasswordUrl: `${config.baseURL}/auth/reset_password/${token}`, resetPasswordUrl: `${config.baseURL}/auth/reset_password/${token}`,
first_name: user.firstName, first_name: user.firstName,
last_name: user.lastName, last_name: user.lastName,
contact_us_email: config.contactUsMail, })
}); .send();
await mail.send();
} }
} }

View File

@@ -1,19 +0,0 @@
import { Service, Inject } from 'typedi';
import { ISystemUser, ITenant } from '@/interfaces';
@Service()
export default class AuthenticationSMSMessages {
@Inject('SMSClient')
smsClient: any;
/**
* Sends welcome sms message.
* @param {ITenant} tenant
* @param {ISystemUser} user
*/
sendWelcomeMessage(tenant: ITenant, user: ISystemUser) {
const message: string = `Hi ${user.firstName}, Welcome to Bigcapital, You've joined the new workspace, if you need any help please don't hesitate to contact us.`;
return this.smsClient.sendMessage(user.phoneNumber, message);
}
}

View File

@@ -25,8 +25,8 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the common entry of cashflow transaction. * Retrieves the common entry of cashflow transaction.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @returns {} * @returns {Partial<ILedgerEntry>}
*/ */
private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => { private getCommonEntry = (cashflowTransaction: ICashflowTransaction) => {
const { entries, ...transaction } = cashflowTransaction; const { entries, ...transaction } = cashflowTransaction;
@@ -41,7 +41,9 @@ export default class CashflowTransactionJournalEntries {
), ),
transactionId: transaction.id, transactionId: transaction.id,
transactionNumber: transaction.transactionNumber, transactionNumber: transaction.transactionNumber,
referenceNo: transaction.referenceNo, referenceNumber: transaction.referenceNo,
note: transaction.description,
branchId: cashflowTransaction.branchId, branchId: cashflowTransaction.branchId,
userId: cashflowTransaction.userId, userId: cashflowTransaction.userId,
@@ -76,9 +78,9 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the cashflow credit GL entry. * Retrieves the cashflow credit GL entry.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @param {ICashflowTransactionLine} entry * @param {ICashflowTransactionLine} entry
* @param {number} index * @param {number} index
* @returns {ILedgerEntry} * @returns {ILedgerEntry}
*/ */
private getCashflowCreditGLEntry = ( private getCashflowCreditGLEntry = (
@@ -102,10 +104,10 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the cashflow transaction GL entry. * Retrieves the cashflow transaction GL entry.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @param {ICashflowTransactionLine} entry * @param {ICashflowTransactionLine} entry
* @param {number} index * @param {number} index
* @returns * @returns {ILedgerEntry[]}
*/ */
private getJournalEntries = ( private getJournalEntries = (
cashflowTransaction: ICashflowTransaction cashflowTransaction: ICashflowTransaction
@@ -118,7 +120,7 @@ export default class CashflowTransactionJournalEntries {
/** /**
* Retrieves the cashflow GL ledger. * Retrieves the cashflow GL ledger.
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @returns {Ledger} * @returns {Ledger}
*/ */
private getCashflowLedger = (cashflowTransaction: ICashflowTransaction) => { private getCashflowLedger = (cashflowTransaction: ICashflowTransaction) => {
@@ -130,6 +132,7 @@ export default class CashflowTransactionJournalEntries {
* Write the journal entries of the given cashflow transaction. * Write the journal entries of the given cashflow transaction.
* @param {number} tenantId * @param {number} tenantId
* @param {ICashflowTransaction} cashflowTransaction * @param {ICashflowTransaction} cashflowTransaction
* @return {Promise<void>}
*/ */
public writeJournalEntries = async ( public writeJournalEntries = async (
tenantId: number, tenantId: number,
@@ -153,6 +156,7 @@ export default class CashflowTransactionJournalEntries {
* Delete the journal entries. * Delete the journal entries.
* @param {number} tenantId - Tenant id. * @param {number} tenantId - Tenant id.
* @param {number} cashflowTransactionId - Cashflow transaction id. * @param {number} cashflowTransactionId - Cashflow transaction id.
* @return {Promise<void>}
*/ */
public revertJournalEntries = async ( public revertJournalEntries = async (
tenantId: number, tenantId: number,

View File

@@ -55,7 +55,7 @@ export class CreateCustomer {
} as ICustomerEventCreatingPayload); } as ICustomerEventCreatingPayload);
// Creates a new contact as customer. // Creates a new contact as customer.
const customer = await Contact.query().insertAndFetch({ const customer = await Contact.query(trx).insertAndFetch({
...customerObj, ...customerObj,
}); });
// Triggers `onCustomerCreated` event. // Triggers `onCustomerCreated` event.

View File

@@ -9,7 +9,6 @@ import events from '@/subscribers/events';
import UnitOfWork from '@/services/UnitOfWork'; import UnitOfWork from '@/services/UnitOfWork';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { CommandExpenseValidator } from './CommandExpenseValidator'; import { CommandExpenseValidator } from './CommandExpenseValidator';
import { ExpenseCategory } from 'models';
import HasTenancyService from '@/services/Tenancy/TenancyService'; import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service() @Service()
@@ -37,7 +36,7 @@ export class DeleteExpense {
expenseId: number, expenseId: number,
authorizedUser: ISystemUser authorizedUser: ISystemUser
): Promise<void> => { ): Promise<void> => {
const { Expense } = this.tenancy.models(tenantId); const { Expense, ExpenseCategory } = this.tenancy.models(tenantId);
// Retrieves the expense transaction with associated entries or // Retrieves the expense transaction with associated entries or
// throw not found error. // throw not found error.
@@ -60,7 +59,7 @@ export class DeleteExpense {
} as IExpenseDeletingPayload); } as IExpenseDeletingPayload);
// Deletes expense associated entries. // Deletes expense associated entries.
await ExpenseCategory.query(trx).findById(expenseId).delete(); await ExpenseCategory.query(trx).where('expenseId', expenseId).delete();
// Deletes expense transactions. // Deletes expense transactions.
await Expense.query(trx).findById(expenseId).delete(); await Expense.query(trx).findById(expenseId).delete();

View File

@@ -46,7 +46,7 @@ export class ExpenseGLEntries {
...commonEntry, ...commonEntry,
credit: expense.localAmount, credit: expense.localAmount,
accountId: expense.paymentAccountId, accountId: expense.paymentAccountId,
accountNormal: AccountNormal.CREDIT, accountNormal: AccountNormal.DEBIT,
index: 1, index: 1,
}; };
}; };

View File

@@ -4,7 +4,7 @@ import events from '@/subscribers/events';
@Service() @Service()
export default class AuthenticationSubscriber { export default class AuthenticationSubscriber {
@Inject('agenda') @Inject('agenda')
agenda: any; private agenda: any;
/** /**
* Attaches events with handlers. * Attaches events with handlers.

View File

@@ -1,28 +0,0 @@
import { Service, Inject } from 'typedi';
import events from '@/subscribers/events';
@Service()
export default class AuthSendWelcomeMailSubscriber {
@Inject('agenda')
agenda: any;
/**
* Attaches events with handlers.
*/
public attach(bus) {
bus.subscribe(events.auth.signUp, this.sendWelcomeEmailOnceUserRegister);
}
/**
* Sends welcome email once the user register.
*/
private sendWelcomeEmailOnceUserRegister = async (payload) => {
const { tenant, user } = payload;
// Send welcome mail to the user.
await this.agenda.now('welcome-email', {
organizationId: tenant.organizationId,
user,
});
};
}

View File

@@ -1,411 +0,0 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Bigcapital | Reset your password</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
/*All the styling goes here*/
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%; }
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: bold;
line-height: 1.4;
margin: 0;
margin-bottom: 0;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn > tbody > tr > td {
padding-bottom: 15px; }
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #2d95fd;
}
.btn-primary a {
background-color: #2d95fd;
border-color: #2d95fd;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.mb4{
margin-bottom: 4rem;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #004dd0 !important;
}
.btn-primary a:hover {
background-color: #004dd0 !important;
border-color: #004dd0 !important;
}
}
[data-icon="bigcapital"] path {
fill: #004dd0;
}
[data-icon='bigcapital'] .path-1,
[data-icon='bigcapital'] .path-13 {
fill: #2d95fd;
}
</style>
</head>
<body class="">
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="align-center">
<svg data-icon="bigcapital" class="bigcapital" width="190" height="37" viewBox="0 0 309.09 42.89"><desc>bigcapital</desc><path d="M56,3.16,61.33,8.5,31.94,37.9l-5.35-5.35Z" class="path-1" fill-rule="evenodd"></path><path d="M29.53,6.94l5.35,5.34L5.49,41.67.14,36.33l15.8-15.8Z" class="path-2" fill-rule="evenodd"></path><path d="M94.36,38.87H79.62v-31H94c6.33,0,10.22,3.15,10.22,8V16a7.22,7.22,0,0,1-4.07,6.69c3.58,1.37,5.8,3.45,5.8,7.61v.09C106,36,101.35,38.87,94.36,38.87Zm3.1-21.81c0-2-1.59-3.19-4.47-3.19H86.26v6.55h6.29c3,0,4.91-1,4.91-3.28Zm1.72,12.39c0-2.08-1.54-3.37-5-3.37H86.26V32.9h8.1c3,0,4.82-1.06,4.82-3.36Z" class="path-3" fill-rule="evenodd"></path><path d="M110.56,12.54v-6h7.08v6Zm.18,26.33V15.15h6.72V38.87Z" class="path-4" fill-rule="evenodd"></path><path d="M134,46a22.55,22.55,0,0,1-10.49-2.47l2.3-5a15.52,15.52,0,0,0,8,2.17c4.61,0,6.78-2.21,6.78-6.46V33.08c-2,2.39-4.16,3.85-7.75,3.85-5.53,0-10.53-4-10.53-11.07v-.09c0-7.08,5.09-11.06,10.53-11.06a9.63,9.63,0,0,1,7.66,3.54v-3.1h6.72V33.52C147.2,42.46,142.78,46,134,46Zm6.6-20.27a5.79,5.79,0,0,0-11.56,0v.09a5.42,5.42,0,0,0,5.76,5.49,5.49,5.49,0,0,0,5.8-5.49Z" class="path-5" fill-rule="evenodd"></path><path d="M164,39.41a12.11,12.11,0,0,1-12.35-12.26v-.09a12.18,12.18,0,0,1,12.44-12.35c4.47,0,7.25,1.5,9.47,4l-4.12,4.43a6.93,6.93,0,0,0-5.4-2.61c-3.36,0-5.75,3-5.75,6.46v.09c0,3.63,2.34,6.55,6,6.55,2.26,0,3.8-1,5.44-2.53l3.94,4A12,12,0,0,1,164,39.41Z" class="path-6" fill-rule="evenodd"></path><path d="M191.51,38.87V36.31a9.15,9.15,0,0,1-7.17,3c-4.47,0-8.15-2.57-8.15-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.72-4.34-5.09-4.34a17.57,17.57,0,0,0-6.55,1.28l-1.68-5.13a21,21,0,0,1,9.21-1.9c7.34,0,10.57,3.8,10.57,10.22V38.87Zm.13-9.55a10.3,10.3,0,0,0-4.29-.89c-2.88,0-4.65,1.15-4.65,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.15,0,5.27-1.73,5.27-4.16Z" class="path-7" fill-rule="evenodd"></path><path d="M217.49,39.32a9.1,9.1,0,0,1-7.39-3.54V46h-6.73V15.15h6.73v3.41a8.7,8.7,0,0,1,7.39-3.85c5.53,0,10.8,4.34,10.8,12.26v.09C228.29,35,223.11,39.32,217.49,39.32ZM221.56,27c0-3.94-2.66-6.55-5.8-6.55S210,23,210,27v.09c0,3.94,2.61,6.55,5.75,6.55s5.8-2.57,5.8-6.55Z" class="path-8" fill-rule="evenodd"></path><path d="M232.93,12.54v-6H240v6Zm.18,26.33V15.15h6.73V38.87Z" class="path-9" fill-rule="evenodd"></path><path d="M253.73,39.27c-4.11,0-6.9-1.63-6.9-7.12V20.91H244V15.15h2.83V9.09h6.73v6.06h5.57v5.76h-5.57V31c0,1.55.66,2.3,2.16,2.3A6.84,6.84,0,0,0,259,32.5v5.4A9.9,9.9,0,0,1,253.73,39.27Z" class="path-10" fill-rule="evenodd"></path><path d="M277.55,38.87V36.31a9.15,9.15,0,0,1-7.18,3c-4.46,0-8.14-2.57-8.14-7.26V32c0-5.18,3.94-7.57,9.56-7.57a16.74,16.74,0,0,1,5.8,1V25c0-2.79-1.73-4.34-5.09-4.34A17.57,17.57,0,0,0,266,21.92l-1.68-5.13a20.94,20.94,0,0,1,9.2-1.9c7.35,0,10.58,3.8,10.58,10.22V38.87Zm.13-9.55a10.31,10.31,0,0,0-4.3-.89c-2.87,0-4.64,1.15-4.64,3.27v.09c0,1.82,1.5,2.88,3.67,2.88,3.14,0,5.27-1.73,5.27-4.16Z" class="path-11" fill-rule="evenodd"></path><path d="M289.72,38.87V6.57h6.72v32.3Z" class="path-12" fill-rule="evenodd"></path><path d="M302.06,38.87V31.79h7.17v7.08Z" class="path-13" fill-rule="evenodd"></path></svg>
</p>
<hr />
<p class="align-center">
<h3>License Code</h3>
</p>
<p class="mgb-1x">
<h1>{{ licenseCode }}</h1>
</p>
<p class="email-note">
This is an automatically generated email please do not reply to
this email. If you face any issues, please contact us at <a href="mailto:{{ successEmail }}">{{ successEmail }}</a> or call <u>{{ successPhoneNumber }}</u></p>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- END CENTERED WHITE CONTAINER -->
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block powered-by">
Powered by <a href="http://htmlemail.io">Bigcapital.com</a>.
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@@ -391,10 +391,8 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<p>If you did not make this request, please contact us or ignore this message.</p> <p>If this was a mistake, just ignore this email and nothing will happen.</p>
<p class="email-note"> <p class="email-note">This is an automatically generated email please do not reply to this email.</p>
This is an automatically generated email please do not reply to
this email. If you face any issues, please contact us at {{ contact_us_email }}</p>
</td> </td>
</tr> </tr>
</table> </table>

View File

@@ -1,407 +0,0 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Bigcapital | Reset your password</title>
<style>
/* -------------------------------------
GLOBAL RESETS
------------------------------------- */
img {
border: none;
-ms-interpolation-mode: bicubic;
max-width: 100%;
}
body {
background-color: #f6f6f6;
font-family: sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
line-height: 1.4;
margin: 0;
padding: 0;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table {
border-collapse: separate;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
width: 100%; }
table td {
font-family: sans-serif;
font-size: 14px;
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
.body {
background-color: #f6f6f6;
width: 100%;
}
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block;
margin: 0 auto !important;
/* makes it centered */
max-width: 580px;
padding: 10px;
width: 580px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
box-sizing: border-box;
display: block;
margin: 0 auto;
max-width: 580px;
padding: 10px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #ffffff;
border-radius: 3px;
width: 100%;
}
.wrapper {
box-sizing: border-box;
padding: 20px;
}
.content-block {
padding-bottom: 10px;
padding-top: 10px;
}
.footer {
clear: both;
margin-top: 10px;
text-align: center;
width: 100%;
}
.footer td,
.footer p,
.footer span,
.footer a {
color: #999999;
font-size: 12px;
text-align: center;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1,
h2,
h3,
h4 {
color: #000000;
font-family: sans-serif;
font-weight: bold;
line-height: 1.4;
margin: 0;
margin-bottom: 0;
}
h1 {
font-size: 35px;
font-weight: 300;
text-align: center;
text-transform: capitalize;
}
p,
ul,
ol {
font-family: sans-serif;
font-size: 14px;
font-weight: normal;
margin: 0;
margin-bottom: 15px;
}
p li,
ul li,
ol li {
list-style-position: inside;
margin-left: 5px;
}
a {
color: #3498db;
text-decoration: underline;
}
/* -------------------------------------
BUTTONS
------------------------------------- */
.btn {
box-sizing: border-box;
width: 100%;
}
.btn > tbody > tr > td {
padding-bottom: 15px; }
.btn table {
width: auto;
}
.btn table td {
background-color: #ffffff;
border-radius: 5px;
text-align: center;
}
.btn a {
background-color: #ffffff;
border: solid 1px #3498db;
border-radius: 5px;
box-sizing: border-box;
color: #3498db;
cursor: pointer;
display: inline-block;
font-size: 14px;
font-weight: bold;
margin: 0;
padding: 12px 25px;
text-decoration: none;
text-transform: capitalize;
}
.btn-primary table td {
background-color: #2d95fd;
}
.btn-primary a {
background-color: #2d95fd;
border-color: #2d95fd;
color: #ffffff;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
.clear {
clear: both;
}
.mt0 {
margin-top: 0;
}
.mb0 {
margin-bottom: 0;
}
.mb4{
margin-bottom: 4rem;
}
.preheader {
color: transparent;
display: none;
height: 0;
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
mso-hide: all;
visibility: hidden;
width: 0;
}
.powered-by a {
text-decoration: none;
}
hr {
border: 0;
border-bottom: 1px solid #f6f6f6;
margin: 20px 0;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #004dd0 !important;
}
.btn-primary a:hover {
background-color: #004dd0 !important;
border-color: #004dd0 !important;
}
}
[data-icon="bigcapital"] path {
fill: #004dd0;
}
[data-icon='bigcapital'] .path-1,
[data-icon='bigcapital'] .path-13 {
fill: #2d95fd;
}
</style>
</head>
<body class="">
<span class="preheader">This is preheader text. Some clients will show this text as a preview.</span>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<p class="align-center">
<img src="cid:bigcapital_logo" />
</p>
<hr />
<p class="align-center">
<h3>Hi {{ firstName }}, Welcome to Bigcapital, </h3>
</p>
<p class="mgb-1x">
Your organization Id: <strong>{{ organizationId }}</strong>
</p>
<p class="mgb-1x">We are available to help you get started and answer any questions you may have. You can also email <a href="mailto:{{ successEmail }}">{{ successEmail }}</a> or call <u>{{ successPhoneNumber }}</u> about your set-up questions.</p>
<p class="mgb-2-5x">Thank you for trusting Bigcapital Software for your business needs. We look forward to serving you!</p>
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- END CENTERED WHITE CONTAINER -->
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block powered-by">
Made by Bigcapital Technologies, Inc
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</div>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@@ -1,7 +1,18 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack');
const dotenv = require('dotenv-webpack');
module.exports = { module.exports = {
webpack: { webpack: {
plugins: [
new dotenv(),
new webpack.DefinePlugin({
'process.env': {
MONOREPO_VERSION: JSON.stringify(require('../../lerna.json').version),
},
}),
],
alias: { alias: {
'@': path.resolve(__dirname, 'src'), '@': path.resolve(__dirname, 'src'),
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bigcapital/webapp", "name": "@bigcapital/webapp",
"version": "1.7.1", "version": "0.9.6",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -1205,9 +1205,9 @@
} }
}, },
"@blueprintjs-formik/core": { "@blueprintjs-formik/core": {
"version": "0.3.3", "version": "0.3.4",
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/core/-/core-0.3.3.tgz", "resolved": "https://registry.npmjs.org/@blueprintjs-formik/core/-/core-0.3.4.tgz",
"integrity": "sha512-ko7g54YSEcSq2K/GEpmiTG0foGLqe7DwgXGhkGxYEiHhLAUv8WvQmrFsm8e/KOW7n8mLGq0uaZVe2l8m3JTGGQ==", "integrity": "sha512-gksuBYXXvX7IhZXbPEFEAHgmJWp1vt/GTMW0GYBkCoGBAvXy08hIHjMc85M0WNyen+tic3NRas6I2wsjgokgqw==",
"requires": { "requires": {
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.keyby": "^4.6.0", "lodash.keyby": "^4.6.0",
@@ -1227,9 +1227,9 @@
} }
}, },
"@blueprintjs-formik/select": { "@blueprintjs-formik/select": {
"version": "0.2.3", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.3.tgz", "resolved": "https://registry.npmjs.org/@blueprintjs-formik/select/-/select-0.2.5.tgz",
"integrity": "sha512-j/zkX0B9wgtoHgK6Z/rlowB7F7zemrAajBU+d3caCoEYMMqwAI0XA++GytqrIhv5fEGjkZ1hkxS9j8eqX8vtjA==", "integrity": "sha512-Sztf5dOemedUBfEjnDWD8ryfMU/x95hyhIgJT5/ywC/jQfX+d/K2OhujklTrCDzQilUeAJLoVkSdV+w77n8ckQ==",
"requires": { "requires": {
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.keyby": "^4.6.0", "lodash.keyby": "^4.6.0",
@@ -1929,137 +1929,6 @@
"reselect": "^4.1.7" "reselect": "^4.1.7"
} }
}, },
"@sentry/browser": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.19.7.tgz",
"integrity": "sha512-oDbklp4O3MtAM4mtuwyZLrgO1qDVYIujzNJQzXmi9YzymJCuzMLSRDvhY83NNDCRxf0pds4DShgYeZdbSyKraA==",
"requires": {
"@sentry/core": "6.19.7",
"@sentry/types": "6.19.7",
"@sentry/utils": "6.19.7",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/core": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz",
"integrity": "sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==",
"requires": {
"@sentry/hub": "6.19.7",
"@sentry/minimal": "6.19.7",
"@sentry/types": "6.19.7",
"@sentry/utils": "6.19.7",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/hub": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.19.7.tgz",
"integrity": "sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==",
"requires": {
"@sentry/types": "6.19.7",
"@sentry/utils": "6.19.7",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/minimal": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.19.7.tgz",
"integrity": "sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==",
"requires": {
"@sentry/hub": "6.19.7",
"@sentry/types": "6.19.7",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/react": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-6.19.7.tgz",
"integrity": "sha512-VzJeBg/v41jfxUYPkH2WYrKjWc4YiMLzDX0f4Zf6WkJ4v3IlDDSkX6DfmWekjTKBho6wiMkSNy2hJ1dHfGZ9jA==",
"requires": {
"@sentry/browser": "6.19.7",
"@sentry/minimal": "6.19.7",
"@sentry/types": "6.19.7",
"@sentry/utils": "6.19.7",
"hoist-non-react-statics": "^3.3.2",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/tracing": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.19.7.tgz",
"integrity": "sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA==",
"requires": {
"@sentry/hub": "6.19.7",
"@sentry/minimal": "6.19.7",
"@sentry/types": "6.19.7",
"@sentry/utils": "6.19.7",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/types": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.19.7.tgz",
"integrity": "sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg=="
},
"@sentry/utils": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.19.7.tgz",
"integrity": "sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==",
"requires": {
"@sentry/types": "6.19.7",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sheerun/mutationobserver-shim": { "@sheerun/mutationobserver-shim": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz", "resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",
@@ -5985,11 +5854,27 @@
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
}, },
"dotenv-defaults": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz",
"integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==",
"requires": {
"dotenv": "^8.2.0"
}
},
"dotenv-expand": { "dotenv-expand": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
}, },
"dotenv-webpack": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.0.1.tgz",
"integrity": "sha512-CdrgfhZOnx4uB18SgaoP9XHRN2v48BbjuXQsZY5ixs5A8579NxQkmMxRtI7aTwSiSQcM2ao12Fdu+L3ZS3bG4w==",
"requires": {
"dotenv-defaults": "^2.0.2"
}
},
"duplexer": { "duplexer": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",

View File

@@ -1,11 +1,11 @@
{ {
"name": "@bigcapital/webapp", "name": "@bigcapital/webapp",
"version": "1.7.1", "version": "0.9.6",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@blueprintjs-formik/core": "^0.3.3", "@blueprintjs-formik/core": "^0.3.4",
"@blueprintjs-formik/datetime": "^0.3.4", "@blueprintjs-formik/datetime": "^0.3.4",
"@blueprintjs-formik/select": "^0.2.3", "@blueprintjs-formik/select": "^0.2.5",
"@blueprintjs/core": "^3.50.2", "@blueprintjs/core": "^3.50.2",
"@blueprintjs/datetime": "^3.23.12", "@blueprintjs/datetime": "^3.23.12",
"@blueprintjs/popover2": "^0.11.1", "@blueprintjs/popover2": "^0.11.1",
@@ -42,6 +42,7 @@
"deep-map-keys": "^2.0.1", "deep-map-keys": "^2.0.1",
"deepdash": "^5.3.9", "deepdash": "^5.3.9",
"dependency-graph": "^0.11.0", "dependency-graph": "^0.11.0",
"dotenv-webpack": "^8.0.1",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"flat": "^5.0.2", "flat": "^5.0.2",
"formik": "^2.2.5", "formik": "^2.2.5",

View File

@@ -5,59 +5,20 @@ import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
/** /**
* * Branch select field.
* @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 {*} film
* @param {*} param1
* @returns
*/
const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
const text = `${branch.name}`;
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
label={branch.code}
key={branch.id}
onClick={handleClick}
text={text}
/>
);
};
const branchSelectProps = {
itemPredicate: branchItemPredicate,
itemRenderer: branchItemRenderer,
valueAccessor: 'id',
labelAccessor: 'name',
};
/**
*
* @param {*} param0 * @param {*} param0
* @returns * @returns {JSX.Element}
*/ */
export function BranchSelect({ branches, ...rest }) { export function BranchSelect({ branches, ...rest }) {
return <FSelect {...branchSelectProps} {...rest} items={branches} />; return (
<FSelect
valueAccessor={'id'}
textAccessor={'name'}
labelAccessor={'code'}
{...rest}
items={branches}
/>
);
} }
/** /**

View File

@@ -4,6 +4,7 @@ import * as R from 'ramda';
import { ButtonLink } from '../Button'; import { ButtonLink } from '../Button';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function CustomerDrawerLinkComponent({ function CustomerDrawerLinkComponent({
// #ownProps // #ownProps
@@ -16,7 +17,7 @@ function CustomerDrawerLinkComponent({
}) { }) {
// Handle view customer drawer. // Handle view customer drawer.
const handleCustomerDrawer = (event) => { const handleCustomerDrawer = (event) => {
openDrawer('customer-detail-drawer', { customerId }); openDrawer(DRAWERS.CUSTOMER_DETAILS, { customerId });
event.preventDefault(); event.preventDefault();
}; };

View File

@@ -1,119 +0,0 @@
// @ts-nocheck
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import { FormattedMessage as T } from '@/components';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { MenuItem, Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
import {
itemPredicate,
handleContactRenderer,
createNewItemRenderer,
createNewItemFromQuery,
} from './utils';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function CustomerSelectFieldRoot({
// #withDrawerActions
openDrawer,
// #ownProps
contacts,
initialContactId,
selectedContactId,
defaultSelectText = <T id={'select_contact'} />,
onContactSelected,
popoverFill = false,
disabled = false,
allowCreate,
buttonProps,
...restProps
}) {
const localContacts = useMemo(
() =>
contacts.map((contact) => ({
...contact,
_id: `${contact.id}_${contact.contact_type}`,
})),
[contacts],
);
const initialContact = useMemo(
() => contacts.find((a) => a.id === initialContactId),
[initialContactId, contacts],
);
const [selecetedContact, setSelectedContact] = useState(
initialContact || null,
);
useEffect(() => {
if (typeof selectedContactId !== 'undefined') {
const account = selectedContactId
? contacts.find((a) => a.id === selectedContactId)
: null;
setSelectedContact(account);
}
}, [selectedContactId, contacts, setSelectedContact]);
const handleContactSelect = useCallback(
(contact) => {
if (contact.id) {
setSelectedContact({ ...contact });
onContactSelected && onContactSelected(contact);
} else {
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
}
},
[setSelectedContact, onContactSelected, openDrawer],
);
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
return (
<Select
items={localContacts}
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
itemRenderer={handleContactRenderer}
itemPredicate={itemPredicate}
filterable={true}
disabled={disabled}
onItemSelect={handleContactSelect}
popoverProps={{ minimal: true, usePortal: !popoverFill }}
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
inputProps={{
placeholder: intl.get('filter_'),
}}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
createNewItemPosition={'top'}
{...restProps}
>
<Button
disabled={disabled}
text={
selecetedContact ? selecetedContact.display_name : defaultSelectText
}
{...buttonProps}
/>
</Select>
);
}
export const CustomerSelectField = R.compose(withDrawerActions)(
CustomerSelectFieldRoot,
);

View File

@@ -0,0 +1,48 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
import { FSelect } from '../Forms';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
/**
* Customer select field.
* @returns {React.ReactNode}
*/
function CustomerSelectRoot({
// #withDrawerActions
openDrawer,
// #ownProps
items,
allowCreate,
...props
}) {
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Handles the create item click.
const handleCreateItemClick = () => {
openDrawer(DRAWERS.QUICK_CREATE_CUSTOMER);
};
return (
<FSelect
items={items}
textAccessor={'display_name'}
labelAccessor={'code'}
valueAccessor={'id'}
popoverProps={{ minimal: true, usePortal: true, inline: false }}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
onCreateItemSelect={handleCreateItemClick}
{...props}
/>
);
}
export const CustomersSelect = R.compose(withDrawerActions)(CustomerSelectRoot);

View File

@@ -1,3 +1,3 @@
// @ts-nocheck // @ts-nocheck
export * from './CustomerSelectField';
export * from './CustomerDrawerLink'; export * from './CustomerDrawerLink';
export * from './CustomersSelect';

View File

@@ -53,7 +53,7 @@ function DashboardTopbar({
}; };
return ( return (
<div class="dashboard__topbar"> <div class="dashboard__topbar" data-testId={'dashboard-topbar'}>
<div class="dashboard__topbar-left"> <div class="dashboard__topbar-left">
<div class="dashboard__topbar-sidebar-toggle"> <div class="dashboard__topbar-sidebar-toggle">
<Tooltip <Tooltip

View File

@@ -31,28 +31,28 @@ import { DRAWERS } from '@/constants/drawers';
export default function DrawersContainer() { export default function DrawersContainer() {
return ( return (
<div> <div>
<AccountDrawer name={DRAWERS.ACCOUNT} /> <AccountDrawer name={DRAWERS.ACCOUNT_DETAILS} />
<ManualJournalDrawer name={DRAWERS.JOURNAL} /> <ManualJournalDrawer name={DRAWERS.JOURNAL_DETAILS} />
<ExpenseDrawer name={DRAWERS.EXPENSE} /> <ExpenseDrawer name={DRAWERS.EXPENSE_DETAILS} />
<BillDrawer name={DRAWERS.BILL} /> <BillDrawer name={DRAWERS.BILL_DETAILS} />
<InvoiceDetailDrawer name={DRAWERS.INVOICE} /> <InvoiceDetailDrawer name={DRAWERS.INVOICE_DETAILS} />
<EstimateDetailDrawer name={DRAWERS.ESTIMATE} /> <EstimateDetailDrawer name={DRAWERS.ESTIMATE_DETAILS} />
<ReceiptDetailDrawer name={DRAWERS.RECEIPT} /> <ReceiptDetailDrawer name={DRAWERS.RECEIPT_DETAILS} />
<PaymentReceiveDetailDrawer name={DRAWERS.PAYMENT_RECEIVE} /> <PaymentReceiveDetailDrawer name={DRAWERS.PAYMENT_RECEIVE_DETAILS} />
<PaymentMadeDetailDrawer name={DRAWERS.PAYMENT_MADE} /> <PaymentMadeDetailDrawer name={DRAWERS.PAYMENT_MADE_DETAILS} />
<ItemDetailDrawer name={DRAWERS.ITEM} /> <ItemDetailDrawer name={DRAWERS.ITEM_DETAILS} />
<CustomerDetailsDrawer name={DRAWERS.CUSTOMER} /> <CustomerDetailsDrawer name={DRAWERS.CUSTOMER_DETAILS} />
<VendorDetailsDrawer name={DRAWERS.VENDOR} /> <VendorDetailsDrawer name={DRAWERS.VENDOR_DETAILS} />
<InventoryAdjustmentDetailDrawer name={DRAWERS.INVENTORY_ADJUSTMENT} /> <InventoryAdjustmentDetailDrawer name={DRAWERS.INVENTORY_ADJUSTMENT_DETAILS} />
<CashflowTransactionDetailDrawer name={DRAWERS.CASHFLOW_TRNASACTION} /> <CashflowTransactionDetailDrawer name={DRAWERS.CASHFLOW_TRNASACTION_DETAILS} />
<QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} /> <QuickCreateCustomerDrawer name={DRAWERS.QUICK_CREATE_CUSTOMER} />
<QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} /> <QuickCreateItemDrawer name={DRAWERS.QUICK_CREATE_ITEM} />
<QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} /> <QuickWriteVendorDrawer name={DRAWERS.QUICK_WRITE_VENDOR} />
<CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE} /> <CreditNoteDetailDrawer name={DRAWERS.CREDIT_NOTE_DETAILS} />
<VendorCreditDetailDrawer name={DRAWERS.VENDOR_CREDIT} /> <VendorCreditDetailDrawer name={DRAWERS.VENDOR_CREDIT_DETAILS} />
<RefundCreditNoteDetailDrawer name={DRAWERS.REFUND_CREDIT_NOTE} /> <RefundCreditNoteDetailDrawer name={DRAWERS.REFUND_CREDIT_NOTE_DETAILS} />
<RefundVendorCreditDetailDrawer name={DRAWERS.REFUND_VENDOR_CREDIT} /> <RefundVendorCreditDetailDrawer name={DRAWERS.REFUND_VENDOR_CREDIT_DETAILS} />
<WarehouseTransferDetailDrawer name={DRAWERS.WAREHOUSE_TRANSFER} /> <WarehouseTransferDetailDrawer name={DRAWERS.WAREHOUSE_TRANSFER_DETAILS} />
</div> </div>
); );
} }

View File

@@ -16,7 +16,7 @@ export function FSelect({ ...props }) {
/> />
); );
}; };
return <Select input={input} {...props} fill={true} />; return <Select input={input} fill={true} {...props} />;
} }
const SelectButton = styled(Button)` const SelectButton = styled(Button)`

View File

@@ -0,0 +1,27 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { Button } from '@blueprintjs/core';
import { Icon } from '@/components';
export function FormWarehouseSelectButton({ text }) {
return (
<Button
text={intl.get('page_form.warehouse_button.label', { text })}
minimal={true}
small={true}
icon={<Icon icon={'warehouse-16'} iconSize={16} />}
/>
);
}
export function FormBranchSelectButton({ text }) {
return (
<Button
text={intl.get('page_form.branch_button.label', { text })}
minimal={true}
small={true}
icon={<Icon icon={'branch-16'} iconSize={16} />}
/>
);
}

View File

@@ -1,3 +1,4 @@
// @ts-nocheck // @ts-nocheck
export * from './FormTopbar'; export * from './FormTopbar';
export * from './FormTopbarSelectInputs';
export * from './PageFormBigNumber'; export * from './PageFormBigNumber';

View File

@@ -4,6 +4,7 @@ import * as R from 'ramda';
import { ButtonLink } from '../Button'; import { ButtonLink } from '../Button';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function VendorDrawerLinkComponent({ function VendorDrawerLinkComponent({
// #ownProps // #ownProps
@@ -16,7 +17,7 @@ function VendorDrawerLinkComponent({
}) { }) {
// Handle view customer drawer. // Handle view customer drawer.
const handleVendorDrawer = (event) => { const handleVendorDrawer = (event) => {
openDrawer('vendor-detail-drawer', { vendorId }); openDrawer(DRAWERS.VENDOR_DETAILS, { vendorId });
event.preventDefault(); event.preventDefault();
}; };

View File

@@ -1,118 +0,0 @@
// @ts-nocheck
import React, { useCallback, useState, useEffect, useMemo } from 'react';
import { FormattedMessage as T } from '@/components';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { MenuItem, Button } from '@blueprintjs/core';
import { Select } from '@blueprintjs/select';
import classNames from 'classnames';
import { CLASSES } from '@/constants/classes';
import {
itemPredicate,
handleContactRenderer,
createNewItemFromQuery,
createNewItemRenderer,
} from './utils';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
function VendorSelectFieldRoot({
// #withDrawerActions
openDrawer,
// #ownProps
contacts,
initialContactId,
selectedContactId,
defaultSelectText = <T id={'select_contact'} />,
onContactSelected,
popoverFill = false,
disabled = false,
allowCreate,
buttonProps,
...restProps
}) {
const localContacts = useMemo(
() =>
contacts.map((contact) => ({
...contact,
_id: `${contact.id}_${contact.contact_type}`,
})),
[contacts],
);
const initialContact = useMemo(
() => contacts.find((a) => a.id === initialContactId),
[initialContactId, contacts],
);
const [selecetedContact, setSelectedContact] = useState(
initialContact || null,
);
useEffect(() => {
if (typeof selectedContactId !== 'undefined') {
const account = selectedContactId
? contacts.find((a) => a.id === selectedContactId)
: null;
setSelectedContact(account);
}
}, [selectedContactId, contacts, setSelectedContact]);
const handleContactSelect = useCallback(
(contact) => {
if (contact.id) {
setSelectedContact({ ...contact });
onContactSelected && onContactSelected(contact);
} else {
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
}
},
[setSelectedContact, onContactSelected, openDrawer],
);
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
return (
<Select
items={localContacts}
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
itemRenderer={handleContactRenderer}
itemPredicate={itemPredicate}
filterable={true}
disabled={disabled}
onItemSelect={handleContactSelect}
popoverProps={{ minimal: true, usePortal: !popoverFill }}
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
})}
inputProps={{
placeholder: intl.get('filter_'),
}}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
createNewItemPosition={'top'}
{...restProps}
>
<Button
disabled={disabled}
text={
selecetedContact ? selecetedContact.display_name : defaultSelectText
}
{...buttonProps}
/>
</Select>
);
}
export const VendorSelectField = R.compose(withDrawerActions)(
VendorSelectFieldRoot,
);

View File

@@ -0,0 +1,49 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { createNewItemFromQuery, createNewItemRenderer } from './utils';
import { FSelect } from '../Forms';
import { DRAWERS } from '@/constants/drawers';
/**
* Vendor select.
* @returns {React.ReactNode}
*/
function VendorsSelectRoot({
// #withDrawerActions
openDrawer,
// #ownProps
items,
allowCreate,
...restProps
}) {
// Maybe inject create new item props to suggest component.
const maybeCreateNewItemRenderer = allowCreate ? createNewItemRenderer : null;
const maybeCreateNewItemFromQuery = allowCreate
? createNewItemFromQuery
: null;
// Handles the create item click.
const handleCreateItemClick = () => {
openDrawer(DRAWERS.QUICK_WRITE_VENDOR);
};
return (
<FSelect
items={items}
textAccessor={'display_name'}
labelAccessor={'code'}
valueAccessor={'id'}
popoverProps={{ minimal: true, usePortal: true, inline: false }}
createNewItemRenderer={maybeCreateNewItemRenderer}
createNewItemFromQuery={maybeCreateNewItemFromQuery}
onCreateItemSelect={handleCreateItemClick}
{...restProps}
/>
);
}
export const VendorsSelect = R.compose(withDrawerActions)(VendorsSelectRoot);

View File

@@ -1,3 +1,3 @@
// @ts-nocheck // @ts-nocheck
export * from './VendorDrawerLink' export * from './VendorDrawerLink'
export * from './VendorSelectField' export * from './VendorsSelect';

View File

@@ -1,75 +1,21 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect } from '../Forms'; import { FSelect } from '../Forms';
/** /**
* * Warehouse select field.
* @param {*} query
* @param {*} warehouse
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
const warehouseItemPredicate = (query, warehouse, _index, exactMatch) => {
const normalizedTitle = warehouse.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return (
`${warehouse.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0
);
}
};
/**
*
* @param {*} film
* @param {*} param1
* @returns
*/
const warehouseItemRenderer = (
warehouse,
{ handleClick, modifiers, query },
) => {
const text = `${warehouse.name}`;
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
label={warehouse.code}
key={warehouse.id}
onClick={handleClick}
text={text}
/>
);
};
const warehouseSelectProps = {
itemPredicate: warehouseItemPredicate,
itemRenderer: warehouseItemRenderer,
valueAccessor: 'id',
labelAccessor: 'name',
};
/**
*
* @param {*} param0 * @param {*} param0
* @returns * @returns
*/ */
export function WarehouseSelect({ warehouses, ...rest }) { export function WarehouseSelect({ warehouses, ...rest }) {
return <FSelect {...warehouseSelectProps} {...rest} items={warehouses} />; return (
} <FSelect
valueAccessor={'id'}
/** labelAccessor={'code'}
* textAccessor={'name'}
* @param {*} param0 popoverProps={{ minimal: true, usePortal: true, inline: false }}
* @returns {...rest}
*/ items={warehouses}
export function WarehouseSelectButton({ label, ...rest }) { />
return <Button text={label} />; );
} }

View File

@@ -1,7 +0,0 @@
// @ts-nocheck
import intl from 'react-intl-universal';
export default [
{ name: intl.get('decrement'), value: 'decrement' },
{ name: intl.get('increment'), value: 'increment' },
]

View File

@@ -1,25 +1,25 @@
// @ts-nocheck // @ts-nocheck
export enum DRAWERS { export enum DRAWERS {
ACCOUNT = 'account-drawer', ACCOUNT_DETAILS = 'account-drawer',
JOURNAL = 'journal-drawer', JOURNAL_DETAILS = 'journal-drawer',
EXPENSE = 'expense-drawer', EXPENSE_DETAILS = 'expense-drawer',
BILL = 'bill-drawer', BILL_DETAILS = 'bill-drawer',
INVOICE = 'invoice-detail-drawer', INVOICE_DETAILS = 'invoice-detail-drawer',
RECEIPT = 'receipt-detail-drawer', RECEIPT_DETAILS = 'receipt-detail-drawer',
PAYMENT_RECEIVE = 'payment-receive-detail-drawer', PAYMENT_RECEIVE_DETAILS = 'payment-receive-detail-drawer',
PAYMENT_MADE = 'payment-made-drawer', PAYMENT_MADE_DETAILS = 'payment-made-drawer',
ESTIMATE = 'estimate-detail-drawer', ESTIMATE_DETAILS = 'estimate-detail-drawer',
ITEM = 'item-detail-drawer', ITEM_DETAILS = 'item-detail-drawer',
CUSTOMER = 'customer-detail-drawer', CUSTOMER_DETAILS = 'customer-detail-drawer',
VENDOR = 'vendor-detail-drawer', VENDOR_DETAILS = 'vendor-detail-drawer',
INVENTORY_ADJUSTMENT = 'inventory-adjustment-drawer', INVENTORY_ADJUSTMENT_DETAILS = 'inventory-adjustment-drawer',
CASHFLOW_TRNASACTION = 'cashflow-transaction-drawer', CASHFLOW_TRNASACTION_DETAILS = 'cashflow-transaction-drawer',
QUICK_CREATE_CUSTOMER = 'quick-create-customer', QUICK_CREATE_CUSTOMER = 'quick-create-customer',
QUICK_CREATE_ITEM = 'quick-create-item', QUICK_CREATE_ITEM = 'quick-create-item',
QUICK_WRITE_VENDOR = 'quick-write-vendor', QUICK_WRITE_VENDOR = 'quick-write-vendor',
CREDIT_NOTE = 'credit-note-detail-drawer', CREDIT_NOTE_DETAILS = 'credit-note-detail-drawer',
VENDOR_CREDIT = 'vendor-credit-detail-drawer', VENDOR_CREDIT_DETAILS = 'vendor-credit-detail-drawer',
REFUND_CREDIT_NOTE = 'refund-credit-detail-drawer', REFUND_CREDIT_NOTE_DETAILS = 'refund-credit-detail-drawer',
REFUND_VENDOR_CREDIT = 'refund-vendor-detail-drawer', REFUND_VENDOR_CREDIT_DETAILS = 'refund-vendor-detail-drawer',
WAREHOUSE_TRANSFER = 'warehouse-transfer-detail-drawer', WAREHOUSE_TRANSFER_DETAILS = 'warehouse-transfer-detail-drawer',
} }

View File

@@ -4,30 +4,22 @@ import intl from 'react-intl-universal';
export const getFooterLinks = () => [ export const getFooterLinks = () => [
{ {
title: intl.get('blog'), title: intl.get('blog'),
link: '#', link: 'https://docs.bigcapital.ly/blog',
},
{
title: intl.get('community'),
link: 'https://discord.com/invite/c8nPBJafeb',
}, },
{ {
title: intl.get('support'), title: intl.get('support'),
link: '#', link: 'https://discord.com/invite/c8nPBJafeb',
},
{
title: intl.get('service_status'),
link: '#',
},
{
title: intl.get('pricing'),
link: '#',
},
{
title: intl.get('reseller_partner'),
link: '#',
}, },
{ {
title: intl.get('docs'), title: intl.get('docs'),
link: '#', link: 'https://docs.bigcapital.ly',
}, },
{ {
title: 'Bigcapital', title: 'Bigcapital',
link: 'http://bigcapital.ly', link: 'http://bigcapital.ly',
} },
] ];

View File

@@ -4,7 +4,6 @@ export * from './tableStyle';
export * from './features'; export * from './features';
export * from './cellTypes'; export * from './cellTypes';
export * from './classes'; export * from './classes';
export * from './adjustmentType';
export * from './cashflowOptions'; export * from './cashflowOptions';
export const Align = { Left: 'left', Right: 'right', Center: 'center' }; export const Align = { Left: 'left', Right: 'right', Center: 'center' };

View File

@@ -25,13 +25,14 @@ import {
CashflowAction, CashflowAction,
PreferencesAbility, PreferencesAbility,
} from '@/constants/abilityOption'; } from '@/constants/abilityOption';
import { DialogsName } from './dialogs';
export const SidebarMenu = [ export const SidebarMenu = [
// --------------- // ---------------
// # Homepage // # Homepage
// --------------- // ---------------
{ {
text: <T id={'homepage'} />, text: <T id={'sidebar.homepage'} />,
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
disabled: false, disabled: false,
href: '/', href: '/',
@@ -41,20 +42,20 @@ export const SidebarMenu = [
// # Sales & Inventory // # Sales & Inventory
// --------------- // ---------------
{ {
text: <T id={'sales_inventory'} />, text: <T id={'sidebar.sales_inventory'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'items'} />, text: <T id={'sidebar.items'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Items, overlayId: ISidebarMenuOverlayIds.Items,
children: [ children: [
{ {
text: <T id={'items'} />, text: <T id={'sidebar.items'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'items'} />, text: <T id={'sidebar.items'} />,
href: '/items', href: '/items',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -63,7 +64,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'inventory_adjustments'} />, text: <T id={'sidebar.inventory_adjustments'} />,
href: '/inventory-adjustments', href: '/inventory-adjustments',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -71,12 +72,6 @@ export const SidebarMenu = [
ability: InventoryAdjustmentAction.View, ability: InventoryAdjustmentAction.View,
}, },
}, },
{
text: <T id={'sidebar_warehouse_transfer'} />,
href: '/warehouses-transfers',
type: ISidebarMenuItemType.Link,
feature: Features.Warehouses,
},
{ {
text: <T id={'category_list'} />, text: <T id={'category_list'} />,
href: '/items/categories', href: '/items/categories',
@@ -86,31 +81,20 @@ export const SidebarMenu = [
ability: ItemAction.View, ability: ItemAction.View,
}, },
}, },
],
},
{
text: <T id={'New tasks'} />,
type: ISidebarMenuItemType.Group,
children: [
{ {
text: <T id={'New inventory item'} />, text: <T id={'sidebar.warehouse_transfer'} />,
href: '/items/new', href: '/warehouses-transfers',
type: ISidebarMenuItemType.Link,
permission: {
subject: AbilitySubject.Item,
ability: ItemAction.Create,
},
},
{
text: (
<T id={'warehouse_transfer.label.new_warehouse_transfer'} />
),
href: '/warehouses-transfers/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
feature: Features.Warehouses, feature: Features.Warehouses,
}, },
],
},
{
text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group,
children: [
{ {
text: <T id={'New service'} />, text: <T id={'sidebar.new_inventory_item'} />,
href: '/items/new', href: '/items/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -119,15 +103,30 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'New item category'} />, text: <T id={'sidebar.new_service'} />,
href: '/items/categories/new', href: '/items/new',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Link,
dialogName: 'item-category-form',
permission: { permission: {
subject: AbilitySubject.Item, subject: AbilitySubject.Item,
ability: ItemAction.Create, ability: ItemAction.Create,
}, },
}, },
{
text: <T id={'sidebar.new_item_category'} />,
href: '/items/categories/new',
type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.ItemCategoryForm,
permission: {
subject: AbilitySubject.Item,
ability: ItemAction.Create,
},
},
{
text: <T id={'sidebar.new_warehouse_transfer'} />,
href: '/warehouses-transfers/new',
type: ISidebarMenuItemType.Link,
feature: Features.Warehouses,
},
], ],
}, },
], ],
@@ -138,16 +137,16 @@ export const SidebarMenu = [
// # Sales // # Sales
// --------------- // ---------------
{ {
text: <T id={'sales'} />, text: <T id={'sidebar.sales'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Sales, overlayId: ISidebarMenuOverlayIds.Sales,
children: [ children: [
{ {
text: <T id={'sales'} />, text: <T id={'sidebar.sales'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'estimates'} />, text: <T id={'sidebar.estimates'} />,
href: '/estimates', href: '/estimates',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -156,7 +155,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'invoices'} />, text: <T id={'sidebar.invoices'} />,
href: '/invoices', href: '/invoices',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -165,7 +164,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'receipts'} />, text: <T id={'sidebar.receipts'} />,
href: '/receipts', href: '/receipts',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -174,12 +173,12 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sidebar_credit_note'} />, text: <T id={'sidebar.credit_notes'} />,
href: '/credit-notes', href: '/credit-notes',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
}, },
{ {
text: <T id={'payment_receives'} />, text: <T id={'sidebar.payment_receives'} />,
href: '/payment-receives', href: '/payment-receives',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -190,11 +189,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'New tasks'} />, text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'new_estimate'} />, text: <T id={'sidebar.new_estimate'} />,
href: '/estimates/new', href: '/estimates/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -203,7 +202,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'new_invoice'} />, text: <T id={'sidebar.new_invoice'} />,
href: '/invoices/new', href: '/invoices/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -212,7 +211,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'new_receipt'} />, text: <T id={'sidebar.new_receipt'} />,
href: '/receipts/new', href: '/receipts/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -221,12 +220,12 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'credit_note.label.new_credit_note'} />, text: <T id={'sidebar.new_credit_note'} />,
href: '/credit-notes/new', href: '/credit-notes/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
}, },
{ {
text: <T id={'new_payment_receive'} />, text: <T id={'sidebar.new_payment_receive'} />,
href: '/payment-receives/new', href: '/payment-receives/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -242,12 +241,12 @@ export const SidebarMenu = [
// # Purchases // # Purchases
// --------------- // ---------------
{ {
text: <T id={'purchases'} />, text: <T id={'sidebar.purchases'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Purchases, overlayId: ISidebarMenuOverlayIds.Purchases,
children: [ children: [
{ {
text: <T id={'purchases'} />, text: <T id={'sidebar.purchases'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
@@ -276,11 +275,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'New tasks'} />, text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'New purchase invoice'} />, text: <T id={'sidebar.new_purchase_invoice'} />,
href: '/bills/new', href: '/bills/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -289,7 +288,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'vendor_credits.label.new_vendor_credit'} />, text: <T id={'sidebar.new_vendor_credit'} />,
href: '/vendor-credits/new', href: '/vendor-credits/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -298,7 +297,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'new_payment_made'} />, text: <T id={'sidebar.new_payment_made'} />,
href: '/payment-mades/new', href: '/payment-mades/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -314,16 +313,16 @@ export const SidebarMenu = [
// # Contacts // # Contacts
// --------------- // ---------------
{ {
text: <T id={'contacts'} />, text: <T id={'sidebar.contacts'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Contacts, overlayId: ISidebarMenuOverlayIds.Contacts,
children: [ children: [
{ {
text: <T id={'contacts'} />, text: <T id={'sidebar.contacts'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'customers'} />, text: <T id={'sidebar.customers'} />,
href: '/customers', href: '/customers',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -332,7 +331,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'vendors'} />, text: <T id={'sidebar.vendors'} />,
href: '/vendors', href: '/vendors',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -343,11 +342,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'New tasks'} />, text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'new_customer'} />, text: <T id={'sidebar.new_customer'} />,
href: '/customers/new', href: '/customers/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -356,7 +355,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'new_vendor'} />, text: <T id={'sidebar.new_vendor'} />,
href: '/vendors/new', href: '/vendors/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -372,20 +371,20 @@ export const SidebarMenu = [
// # Accounting // # Accounting
// --------------- // ---------------
{ {
text: <T id={'accounting'} />, text: <T id={'sidebar.accounting'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'financial'} />, text: <T id={'sidebar.financial'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Financial, overlayId: ISidebarMenuOverlayIds.Financial,
children: [ children: [
{ {
text: <T id={'financial'} />, text: <T id={'sidebar.financial'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'accounts_chart'} />, text: <T id={'sidebar.accounts_chart'} />,
href: '/accounts', href: '/accounts',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -394,7 +393,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'manual_journals'} />, text: <T id={'sidebar.manual_journals'} />,
href: '/manual-journals', href: '/manual-journals',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -410,11 +409,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'New tasks'} />, text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'make_journal_entry'} />, text: <T id={'sidebar.make_journal_entry'} />,
href: '/make-journal-entry', href: '/make-journal-entry',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -441,7 +440,7 @@ export const SidebarMenu = [
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'siebar.cashflow.label_cash_and_bank_accounts'} />, text: <T id={'sidebar.cash_bank_accounts'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -452,42 +451,45 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'New tasks'} />, text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
divider: true, divider: true,
children: [ children: [
{ {
text: <T id={'cash_flow.label.add_money_in'} />, text: <T id={'sidebar.add_money_in'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: 'money-in', dialogName: DialogsName.MoneyInForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
}, },
}, },
{ {
text: <T id={'cash_flow.label.add_money_out'} />, text: <T id={'sidebar.add_money_out'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.MoneyOutForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
}, },
}, },
{ {
text: <T id={'cash_flow.label.add_cash_account'} />, text: <T id={'sidebar.add_cash_account'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.AccountForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
}, },
}, },
{ {
text: <T id={'cash_flow.label.add_bank_account'} />, text: <T id={'sidebar.add_bank_account'} />,
href: '/cashflow-accounts', href: '/cashflow-accounts',
type: ISidebarMenuItemType.Dialog, type: ISidebarMenuItemType.Dialog,
dialogName: DialogsName.AccountForm,
permission: { permission: {
subject: AbilitySubject.Cashflow, subject: AbilitySubject.Cashflow,
ability: CashflowAction.Create, ability: CashflowAction.Create,
@@ -501,16 +503,16 @@ export const SidebarMenu = [
// # Expenses // # Expenses
// --------------- // ---------------
{ {
text: <T id={'expenses'} />, text: <T id={'sidebar.expenses'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Expenses, overlayId: ISidebarMenuOverlayIds.Expenses,
children: [ children: [
{ {
text: <T id={'expenses'} />, text: <T id={'sidebar.expenses'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'expenses'} />, text: <T id={'sidebar.expenses'} />,
href: '/expenses', href: '/expenses',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -521,11 +523,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'New tasks'} />, text: <T id={'sidebar.new_tasks'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'new_expense'} />, text: <T id={'sidebar.new_expense'} />,
href: '/expenses/new', href: '/expenses/new',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -541,16 +543,16 @@ export const SidebarMenu = [
// # Projects Management // # Projects Management
// --------------------- // ---------------------
// { // {
// text: 'Projects', // text: <T id={'sidebar.projects'} />,
// type: ISidebarMenuItemType.Overlay, // type: ISidebarMenuItemType.Overlay,
// overlayId: ISidebarMenuOverlayIds.Projects, // overlayId: ISidebarMenuOverlayIds.Projects,
// children: [ // children: [
// { // {
// text: 'Projects', // text: <T id={'sidebar.projects'} />,
// type: ISidebarMenuItemType.Group, // type: ISidebarMenuItemType.Group,
// children: [ // children: [
// { // {
// text: 'Projects', // text: <T id={'sidebar.projects'} />,
// href: '/projects', // href: '/projects',
// type: ISidebarMenuItemType.Link, // type: ISidebarMenuItemType.Link,
// permission: { // permission: {
@@ -561,11 +563,11 @@ export const SidebarMenu = [
// ], // ],
// }, // },
// { // {
// text: <T id={'New tasks'} />, // text: <T id={'sidebar.new_tasks'} />,
// type: ISidebarMenuItemType.Group, // type: ISidebarMenuItemType.Group,
// children: [ // children: [
// { // {
// text: <T id={'projects.label.new_project'} />, // text: <T id={'sidebar.new_project'} />,
// type: ISidebarMenuItemType.Dialog, // type: ISidebarMenuItemType.Dialog,
// dialogName: 'project-form', // dialogName: 'project-form',
// permission: { // permission: {
@@ -574,18 +576,18 @@ export const SidebarMenu = [
// }, // },
// }, // },
// { // {
// text: <T id={'projects.label.new_time_entry'} />, // text: <T id={'sidebar.new_time_entry'} />,
// type: ISidebarMenuItemType.Dialog, // type: ISidebarMenuItemType.Dialog,
// dialogName: 'project-time-entry-form', // dialogName: 'project-time-entry-form',
// }, // },
// ], // ],
// }, // },
// { // {
// text: <T id={'Reports'} />, // text: <T id={'sidebar.reports'} />,
// type: ISidebarMenuItemType.Group, // type: ISidebarMenuItemType.Group,
// children: [ // children: [
// { // {
// text: <T id={'project_profitability_summary'} />, // text: <T id={'sidebar.project_profitability_summary'} />,
// href: '/financial-reports/project-profitability-summary', // href: '/financial-reports/project-profitability-summary',
// type: ISidebarMenuItemType.Link, // type: ISidebarMenuItemType.Link,
// }, // },
@@ -597,16 +599,16 @@ export const SidebarMenu = [
// # Reports // # Reports
// --------------- // ---------------
{ {
text: <T id={'Reports'} />, text: <T id={'sidebar.reports'} />,
type: ISidebarMenuItemType.Overlay, type: ISidebarMenuItemType.Overlay,
overlayId: ISidebarMenuOverlayIds.Reports, overlayId: ISidebarMenuOverlayIds.Reports,
children: [ children: [
{ {
text: <T id={'Reports'} />, text: <T id={'sidebar.reports'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'balance_sheet'} />, text: <T id={'sidebar.balance_sheet'} />,
href: '/financial-reports/balance-sheet', href: '/financial-reports/balance-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -615,7 +617,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'trial_balance_sheet'} />, text: <T id={'sidebar.trial_balance_sheet'} />,
href: '/financial-reports/trial-balance-sheet', href: '/financial-reports/trial-balance-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -624,7 +626,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'journal'} />, text: <T id={'sidebar.journal'} />,
href: '/financial-reports/journal-sheet', href: '/financial-reports/journal-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -633,7 +635,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'general_ledger'} />, text: <T id={'sidebar.general_ledger'} />,
href: '/financial-reports/general-ledger', href: '/financial-reports/general-ledger',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -642,7 +644,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'profit_loss_sheet'} />, text: <T id={'sidebar.profit_loss_sheet'} />,
href: '/financial-reports/profit-loss-sheet', href: '/financial-reports/profit-loss-sheet',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -651,7 +653,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'cash_flow_statement'} />, text: <T id={'sidebar.cash_flow_statement'} />,
href: '/financial-reports/cash-flow', href: '/financial-reports/cash-flow',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -660,7 +662,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'AR_Aging_Summary'} />, text: <T id={'sidebar.ar_aging_Summary'} />,
href: '/financial-reports/receivable-aging-summary', href: '/financial-reports/receivable-aging-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -669,7 +671,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'AP_Aging_Summary'} />, text: <T id={'sidebar.ap_aging_summary'} />,
href: '/financial-reports/payable-aging-summary', href: '/financial-reports/payable-aging-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -680,11 +682,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'Sales/Purchases'} />, text: <T id={'sidebar.sales_purchases'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'purchases_by_items'} />, text: <T id={'sidebar.purchases_by_items'} />,
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
href: '/financial-reports/purchases-by-items', href: '/financial-reports/purchases-by-items',
permission: { permission: {
@@ -693,7 +695,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'sales_by_items'} />, text: <T id={'sidebar.sales_by_items'} />,
href: '/financial-reports/sales-by-items', href: '/financial-reports/sales-by-items',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -702,7 +704,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'customers_transactions'} />, text: <T id={'sidebar.customers_transactions'} />,
href: '/financial-reports/transactions-by-customers', href: '/financial-reports/transactions-by-customers',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -711,7 +713,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'vendors_transactions'} />, text: <T id={'sidebar.vendors_transactions'} />,
href: '/financial-reports/transactions-by-vendors', href: '/financial-reports/transactions-by-vendors',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -720,7 +722,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'customers_balance_summary'} />, text: <T id={'sidebar.customers_balance_summary'} />,
href: '/financial-reports/customers-balance-summary', href: '/financial-reports/customers-balance-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -729,7 +731,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'vendors_balance_summary'} />, text: <T id={'sidebar.vendors_balance_summary'} />,
href: '/financial-reports/vendors-balance-summary', href: '/financial-reports/vendors-balance-summary',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -740,11 +742,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'inventory'} />, text: <T id={'sidebar.inventory'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'inventory_item_details'} />, text: <T id={'sidebar.inventory_item_details'} />,
href: '/financial-reports/inventory-item-details', href: '/financial-reports/inventory-item-details',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -753,7 +755,7 @@ export const SidebarMenu = [
}, },
}, },
{ {
text: <T id={'inventory_valuation'} />, text: <T id={'sidebar.inventory_valuation'} />,
href: '/financial-reports/inventory-valuation', href: '/financial-reports/inventory-valuation',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {
@@ -766,11 +768,11 @@ export const SidebarMenu = [
], ],
}, },
{ {
text: <T id={'system'} />, text: <T id={'sidebar.system'} />,
type: ISidebarMenuItemType.Group, type: ISidebarMenuItemType.Group,
children: [ children: [
{ {
text: <T id={'preferences'} />, text: <T id={'sidebar.preferences'} />,
href: '/preferences', href: '/preferences',
type: ISidebarMenuItemType.Link, type: ISidebarMenuItemType.Link,
permission: { permission: {

View File

@@ -25,6 +25,7 @@ import { useMemorizedColumnsWidths } from '@/hooks';
import { useManualJournalsColumns } from './utils'; import { useManualJournalsColumns } from './utils';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Manual journals data-table. * Manual journals data-table.
@@ -79,14 +80,16 @@ function ManualJournalsDataTable({
// Handle view detail journal. // Handle view detail journal.
const handleViewDetailJournal = ({ id }) => { const handleViewDetailJournal = ({ id }) => {
openDrawer('journal-drawer', { openDrawer(DRAWERS.JOURNAL_DETAILS, {
manualJournalId: id, manualJournalId: id,
}); });
}; };
// Handle cell click. // Handle cell click.
const handleCellClick = (cell, event) => { const handleCellClick = (cell, event) => {
openDrawer('journal-drawer', { manualJournalId: cell.row.original.id }); openDrawer(DRAWERS.JOURNAL_DETAILS, {
manualJournalId: cell.row.original.id,
});
}; };
// Local storage memorizing columns widths. // Local storage memorizing columns widths.

View File

@@ -1,193 +0,0 @@
// @ts-nocheck
import React from 'react';
import {
Intent,
Button,
ButtonGroup,
Popover,
PopoverInteractionKind,
Position,
Menu,
MenuItem,
} from '@blueprintjs/core';
import classNames from 'classnames';
import { useFormikContext } from 'formik';
import { FormattedMessage as T, If, Icon } from '@/components';
import { CLASSES } from '@/constants/classes';
import { useMakeJournalFormContext } from './MakeJournalProvider';
import { useHistory } from 'react-router-dom';
/**
* Make Journal floating actions bar.
*/
export default function MakeJournalEntriesFooter() {
const history = useHistory();
// Formik context.
const { isSubmitting, submitForm } = useFormikContext();
// Make journal form context.
const {
manualJournalId,
setSubmitPayload,
manualJournalPublished = false,
} = useMakeJournalFormContext();
// Handle `submit & publish` button click.
const handleSubmitPublishBtnClick = (event) => {
setSubmitPayload({ redirect: true, publish: true });
submitForm();
};
// Handle `submit, publish & new` button click.
const handleSubmitPublishAndNewBtnClick = (event) => {
setSubmitPayload({ redirect: false, publish: true, resetForm: true });
submitForm();
};
// Handle `submit, publish & continue editing` button click.
const handleSubmitPublishContinueEditingBtnClick = (event) => {
setSubmitPayload({ redirect: false, publish: true });
submitForm();
};
// Handle `submit as draft` button click.
const handleSubmitDraftBtnClick = (event) => {
setSubmitPayload({ redirect: true, publish: false });
};
// Handle `submit as draft & new` button click.
const handleSubmitDraftAndNewBtnClick = (event) => {
setSubmitPayload({ redirect: false, publish: false, resetForm: true });
submitForm();
};
// Handles submit as draft & continue editing button click.
const handleSubmitDraftContinueEditingBtnClick = (event) => {
setSubmitPayload({ redirect: false, publish: false });
submitForm();
};
// Handle cancel button action click.
const handleCancelBtnClick = (event) => {
history.goBack();
};
const handleClearBtnClick = (event) => {};
return (
<div className={classNames(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
{/* ----------- Save And Publish ----------- */}
<If condition={!manualJournalId || !manualJournalPublished}>
<ButtonGroup>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
type="submit"
onClick={handleSubmitPublishBtnClick}
text={<T id={'save_publish'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'publish_and_new'} />}
onClick={handleSubmitPublishAndNewBtnClick}
/>
<MenuItem
text={<T id={'publish_continue_editing'} />}
onClick={handleSubmitPublishContinueEditingBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
{/* ----------- Save As Draft ----------- */}
<ButtonGroup>
<Button
disabled={isSubmitting}
className={'ml1'}
type="submit"
onClick={handleSubmitDraftBtnClick}
text={<T id={'save_as_draft'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'save_and_new'} />}
onClick={handleSubmitDraftAndNewBtnClick}
/>
<MenuItem
text={<T id={'save_continue_editing'} />}
onClick={handleSubmitDraftContinueEditingBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
disabled={isSubmitting}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
</If>
{/* ----------- Save and New ----------- */}
<If condition={manualJournalId && manualJournalPublished}>
<ButtonGroup>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
type="submit"
onClick={handleSubmitPublishBtnClick}
text={<T id={'save'} />}
/>
<Popover
content={
<Menu>
<MenuItem
text={<T id={'save_and_new'} />}
onClick={handleSubmitPublishAndNewBtnClick}
/>
</Menu>
}
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
rightIcon={<Icon icon="arrow-drop-up-16" iconSize={20} />}
/>
</Popover>
</ButtonGroup>
</If>
{/* ----------- Clear & Reset----------- */}
<Button
className={'ml1'}
disabled={isSubmitting}
onClick={handleClearBtnClick}
text={manualJournalId ? <T id={'reset'} /> : <T id={'clear'} />}
/>
{/* ----------- Cancel ----------- */}
<Button
className={'ml1'}
onClick={handleCancelBtnClick}
text={<T id={'cancel'} />}
/>
</div>
);
}

View File

@@ -1,14 +1,8 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { import { InputGroup, FormGroup, Position } from '@blueprintjs/core';
InputGroup, import { FastField, ErrorMessage } from 'formik';
FormGroup,
Position,
ControlGroup,
} from '@blueprintjs/core';
import { FastField, ErrorMessage, useFormikContext } from 'formik';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import * as R from 'ramda';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
@@ -20,99 +14,15 @@ import {
} from '@/utils'; } from '@/utils';
import { import {
Hint, Hint,
FieldHint,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
InputPrependButton,
CurrencySelectList, CurrencySelectList,
FormattedMessage as T, FormattedMessage as T,
FInputGroup,
FFormGroup,
} from '@/components'; } from '@/components';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
import { JournalExchangeRateInputField } from './components'; import { JournalExchangeRateInputField } from './components';
import { currenciesFieldShouldUpdate } from './utils'; import { currenciesFieldShouldUpdate } from './utils';
import { MakeJournalTransactionNoField } from './MakeJournalTransactionNoField';
import withSettings from '@/containers/Settings/withSettings';
import withDialogActions from '@/containers/Dialog/withDialogActions';
/**
* Journal number field of make journal form.
*/
const MakeJournalTransactionNoField = R.compose(
withDialogActions,
withSettings(({ manualJournalsSettings }) => ({
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
})),
)(
({
// #withDialog
openDialog,
// #withSettings
journalAutoIncrement,
}) => {
const { setFieldValue, values } = useFormikContext();
const handleJournalNumberChange = () => {
openDialog('journal-number-form');
};
const handleJournalNoBlur = (event) => {
const newValue = event.target.value;
if (values.journal_number !== newValue && journalAutoIncrement) {
openDialog('journal-number-form', {
initialFormValues: {
onceManualNumber: newValue,
incrementMode: 'manual-transaction',
},
});
}
if (!journalAutoIncrement) {
setFieldValue('journal_number', newValue);
setFieldValue('journal_number_manually', newValue);
}
};
return (
<FFormGroup
name={'journal_number'}
label={<T id={'journal_no'} />}
labelInfo={
<>
<FieldRequiredHint />
<FieldHint />
</>
}
fill={true}
inline={true}
fastField={true}
>
<ControlGroup fill={true}>
<FInputGroup
name={'journal_number'}
fill={true}
asyncControl={true}
onBlur={handleJournalNoBlur}
fastField={true}
onChange={() => {}}
/>
<InputPrependButton
buttonProps={{
onClick: handleJournalNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: <T id={'setting_your_auto_generated_journal_number'} />,
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FFormGroup>
);
},
);
/** /**
* Make journal entries header. * Make journal entries header.

View File

@@ -1,6 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import intl from 'react-intl-universal';
import { FFormGroup, FEditableText, FormattedMessage as T } from '@/components'; import { FFormGroup, FEditableText, FormattedMessage as T } from '@/components';
export function MakeJournalFormFooterLeft() { export function MakeJournalFormFooterLeft() {
@@ -13,7 +14,7 @@ export function MakeJournalFormFooterLeft() {
> >
<FEditableText <FEditableText
name={'description'} name={'description'}
placeholder={<T id={'make_jorunal.decscrption.placeholder'} />} placeholder={intl.get('make_jorunal.decscrption.placeholder')}
/> />
</DescriptionFormGroup> </DescriptionFormGroup>
</React.Fragment> </React.Fragment>

View File

@@ -11,6 +11,7 @@ import {
FeatureCan, FeatureCan,
FormTopbar, FormTopbar,
DetailsBarSkeletonBase, DetailsBarSkeletonBase,
FormBranchSelectButton,
} from '@/components'; } from '@/components';
import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useMakeJournalFormContext } from './MakeJournalProvider';
@@ -51,18 +52,9 @@ function MakeJournalFormSelectBranch() {
<BranchSelect <BranchSelect
name={'branch_id'} name={'branch_id'}
branches={branches} branches={branches}
input={MakeJournalBranchSelectButton} input={FormBranchSelectButton}
popoverProps={{ minimal: true }} popoverProps={{ minimal: true }}
/> fill={false}
);
}
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} />}
/> />
); );
} }

View File

@@ -0,0 +1,97 @@
// @ts-nocheck
import React from 'react';
import { Position, ControlGroup } from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import * as R from 'ramda';
import {
FieldHint,
FieldRequiredHint,
Icon,
InputPrependButton,
FormattedMessage as T,
FInputGroup,
FFormGroup,
} from '@/components';
import withSettings from '@/containers/Settings/withSettings';
import withDialogActions from '@/containers/Dialog/withDialogActions';
/**
* Journal number field of make journal form.
*/
export const MakeJournalTransactionNoField = R.compose(
withDialogActions,
withSettings(({ manualJournalsSettings }) => ({
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
})),
)(
({
// #withDialog
openDialog,
// #withSettings
journalAutoIncrement,
}) => {
const { setFieldValue, values } = useFormikContext();
const handleJournalNumberChange = () => {
openDialog('journal-number-form');
};
const handleJournalNoBlur = (event) => {
const newValue = event.target.value;
if (values.journal_number !== newValue && journalAutoIncrement) {
openDialog('journal-number-form', {
initialFormValues: {
onceManualNumber: newValue,
incrementMode: 'manual-transaction',
},
});
}
if (!journalAutoIncrement) {
setFieldValue('journal_number', newValue);
setFieldValue('journal_number_manually', newValue);
}
};
return (
<FFormGroup
name={'journal_number'}
label={<T id={'journal_no'} />}
labelInfo={
<>
<FieldRequiredHint />
<FieldHint />
</>
}
fill={true}
inline={true}
fastField={true}
>
<ControlGroup fill={true}>
<FInputGroup
name={'journal_number'}
fill={true}
asyncControl={true}
onBlur={handleJournalNoBlur}
fastField={true}
onChange={() => {}}
/>
<InputPrependButton
buttonProps={{
onClick: handleJournalNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: <T id={'setting_your_auto_generated_journal_number'} />,
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FFormGroup>
);
},
);
MakeJournalTransactionNoField.displayName = 'MakeJournalTransactionNoField';

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { Menu, MenuItem, Position, Button } from '@blueprintjs/core'; import { Menu, MenuItem, Position, Button, Intent } from '@blueprintjs/core';
import { Popover2 } from '@blueprintjs/popover2'; import { Popover2 } from '@blueprintjs/popover2';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import * as R from 'ramda'; import * as R from 'ramda';
@@ -74,6 +74,7 @@ export const ActionsCellRenderer = ({
const exampleMenu = ( const exampleMenu = (
<Menu> <Menu>
<MenuItem <MenuItem
intent={Intent.DANGER}
onClick={handleClickRemoveRole} onClick={handleClickRemoveRole}
text={intl.get('make_journal.entries.remove_row')} text={intl.get('make_journal.entries.remove_row')}
/> />

View File

@@ -28,6 +28,8 @@ const ERROR = {
CREDIT_DEBIT_SUMATION_SHOULD_NOT_EQUAL_ZERO: CREDIT_DEBIT_SUMATION_SHOULD_NOT_EQUAL_ZERO:
'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO', 'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT', ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
COULD_NOT_ASSIGN_DIFFERENT_CURRENCY_TO_ACCOUNTS:
'COULD_NOT_ASSIGN_DIFFERENT_CURRENCY_TO_ACCOUNTS',
}; };
export const MIN_LINES_NUMBER = 1; export const MIN_LINES_NUMBER = 1;
@@ -161,6 +163,15 @@ export const transformErrors = (resErrors, { setErrors, errors }) => {
intl.get('journal_number_is_already_used'), intl.get('journal_number_is_already_used'),
); );
} }
if (
(error = getError(ERROR.COULD_NOT_ASSIGN_DIFFERENT_CURRENCY_TO_ACCOUNTS))
) {
toastMessages.push(
intl.get(
'make_journal.errors.should_add_accounts_in_same_currency_or_base_currency',
),
);
}
setErrors({ ...newErrors }); setErrors({ ...newErrors });
if (toastMessages.length > 0) { if (toastMessages.length > 0) {

View File

@@ -3,6 +3,7 @@ import intl from 'react-intl-universal';
import { RESOURCES_TYPES } from '@/constants/resourcesTypes'; import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
import { AbilitySubject, ManualJournalAction } from '@/constants/abilityOption'; import { AbilitySubject, ManualJournalAction } from '@/constants/abilityOption';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Universal search manual journal item select action. * Universal search manual journal item select action.
@@ -17,7 +18,7 @@ function JournalUniversalSearchSelectComponent({
openDrawer, openDrawer,
}) { }) {
if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) { if (resourceType === RESOURCES_TYPES.MANUAL_JOURNAL) {
openDrawer('journal-drawer', { manualJournalId: resourceId }); openDrawer(DRAWERS.JOURNAL_DETAILS, { manualJournalId: resourceId });
onAction && onAction(); onAction && onAction();
} }
return null; return null;

View File

@@ -5,6 +5,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { AbilitySubject, AccountAction } from '@/constants/abilityOption'; import { AbilitySubject, AccountAction } from '@/constants/abilityOption';
import { RESOURCES_TYPES } from '@/constants/resourcesTypes'; import { RESOURCES_TYPES } from '@/constants/resourcesTypes';
import { DRAWERS } from '@/constants/drawers';
function AccountUniversalSearchItemSelectComponent({ function AccountUniversalSearchItemSelectComponent({
// #ownProps // #ownProps
@@ -16,7 +17,7 @@ function AccountUniversalSearchItemSelectComponent({
openDrawer, openDrawer,
}) { }) {
if (resourceType === RESOURCES_TYPES.ACCOUNT) { if (resourceType === RESOURCES_TYPES.ACCOUNT) {
openDrawer('account-drawer', { accountId: resourceId }); openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: resourceId });
onAction && onAction(); onAction && onAction();
} }
return null; return null;

View File

@@ -23,6 +23,7 @@ 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';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Accounts data-table. * Accounts data-table.
@@ -71,7 +72,7 @@ function AccountsDataTable({
// Handle view detail account. // Handle view detail account.
const handleViewDetailAccount = ({ id }) => { const handleViewDetailAccount = ({ id }) => {
openDrawer('account-drawer', { accountId: id }); openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: id });
}; };
// Handle new child button click. // Handle new child button click.
@@ -84,7 +85,7 @@ function AccountsDataTable({
}; };
// Handle cell click. // Handle cell click.
const handleCellClick = (cell, event) => { const handleCellClick = (cell, event) => {
openDrawer('account-drawer', { accountId: cell.row.original.id }); openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: cell.row.original.id });
}; };
// Local storage memorizing columns widths. // Local storage memorizing columns widths.
const [initialColumnsWidths, , handleColumnResizing] = const [initialColumnsWidths, , handleColumnResizing] =

View File

@@ -16,6 +16,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteAccount } from '@/hooks/query'; import { useDeleteAccount } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Account delete alerts. * Account delete alerts.
@@ -48,7 +49,7 @@ function AccountDeleteAlert({
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeAlert(name); closeAlert(name);
closeDrawer('account-drawer'); closeDrawer(DRAWERS.ACCOUNT_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -11,6 +11,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { handleDeleteErrors } from '@/containers/Purchases/Bills/BillForm/utils'; import { handleDeleteErrors } from '@/containers/Purchases/Bills/BillForm/utils';
import { useDeleteBill } from '@/hooks/query'; import { useDeleteBill } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Bill delete alert. * Bill delete alert.
@@ -43,8 +44,7 @@ function BillDeleteAlert({
message: intl.get('the_bill_has_been_deleted_successfully'), message: intl.get('the_bill_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer(DRAWERS.BILL_DETAILS);
closeDrawer('bill-drawer');
}) })
.catch( .catch(
({ ({

View File

@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Account delete transaction alert. * Account delete transaction alert.
@@ -48,7 +49,7 @@ function AccountDeleteTransactionAlert({
message: intl.get('cash_flow_transaction.delete.alert_message'), message: intl.get('cash_flow_transaction.delete.alert_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('cashflow-transaction-drawer'); closeDrawer(DRAWERS.CASHFLOW_TRNASACTION_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -15,6 +15,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteCreditNote } from '@/hooks/query'; import { useDeleteCreditNote } from '@/hooks/query';
import { handleDeleteErrors } from '@/containers/Sales/CreditNotes/CreditNotesLanding/utils'; import { handleDeleteErrors } from '@/containers/Sales/CreditNotes/CreditNotesLanding/utils';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Credit note delete alert. * Credit note delete alert.
@@ -46,7 +47,7 @@ function CreditNoteDeleteAlert({
message: intl.get('credit_note.alert.delete_message'), message: intl.get('credit_note.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('credit-note-detail-drawer'); closeDrawer(DRAWERS.CREDIT_NOTE_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -11,6 +11,7 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Refund credit transactions delete alert * Refund credit transactions delete alert
@@ -42,7 +43,7 @@ function RefundCreditNoteDeleteAlert({
message: intl.get('refund_credit_transactions.alert.delete_message'), message: intl.get('refund_credit_transactions.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('refund-credit-detail-drawer'); closeDrawer(DRAWERS.REFUND_CREDIT_NOTE_DETAILS);
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -15,6 +15,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteCustomer } from '@/hooks/query'; import { useDeleteCustomer } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Customer delete alert. * Customer delete alert.
@@ -47,7 +48,7 @@ function CustomerDeleteAlert({
message: intl.get('the_customer_has_been_deleted_successfully'), message: intl.get('the_customer_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('customer-detail-drawer'); closeDrawer(DRAWERS.CUSTOMER_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Estimate delete alert. * Estimate delete alert.
@@ -47,7 +48,7 @@ function EstimateDeleteAlert({
message: intl.get('the_estimate_has_been_deleted_successfully'), message: intl.get('the_estimate_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('estimate-detail-drawer'); closeDrawer(DRAWERS.ESTIMATE_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -10,6 +10,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteExpense } from '@/hooks/query'; import { useDeleteExpense } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Expense delete alert. * Expense delete alert.
@@ -42,7 +43,7 @@ function ExpenseDeleteAlert({
}), }),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('expense-drawer'); closeDrawer(DRAWERS.EXPENSE_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -16,6 +16,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Invoice delete alert. * Invoice delete alert.
@@ -48,7 +49,7 @@ function InvoiceDeleteAlert({
message: intl.get('the_invoice_has_been_deleted_successfully'), message: intl.get('the_invoice_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('invoice-detail-drawer'); closeDrawer(DRAWERS.INVOICE_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -14,6 +14,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeleteInventoryAdjustment } from '@/hooks/query'; import { useDeleteInventoryAdjustment } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Inventory Adjustment delete alerts. * Inventory Adjustment delete alerts.
@@ -49,7 +50,7 @@ function InventoryAdjustmentDeleteAlert({
), ),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('inventory-adjustment-drawer'); closeDrawer(DRAWERS.INVENTORY_ADJUSTMENT_DETAILS);
}) })
.catch((errors) => {}) .catch((errors) => {})
.finally(() => { .finally(() => {

View File

@@ -17,6 +17,7 @@ import withItemsActions from '@/containers/Items/withItemsActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Item delete alerts. * Item delete alerts.
@@ -54,7 +55,7 @@ function ItemDeleteAlert({
}); });
// Reset to page number one. // Reset to page number one.
setItemsTableState({ page: 1 }); setItemsTableState({ page: 1 });
closeDrawer('item-detail-drawer'); closeDrawer(DRAWERS.ITEM_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -10,6 +10,7 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Journal delete alert. * Journal delete alert.
@@ -45,7 +46,7 @@ function JournalDeleteAlert({
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeAlert(name); closeAlert(name);
closeDrawer('journal-drawer'); closeDrawer(DRAWERS.JOURNAL_DETAILS);
}) })
.catch(() => { .catch(() => {
closeAlert(name); closeAlert(name);

View File

@@ -11,6 +11,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useDeletePaymentMade } from '@/hooks/query'; import { useDeletePaymentMade } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Payment made delete alert. * Payment made delete alert.
@@ -44,7 +45,7 @@ function PaymentMadeDeleteAlert({
message: intl.get('the_payment_made_has_been_deleted_successfully'), message: intl.get('the_payment_made_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('payment-made-detail-drawer'); closeDrawer(DRAWERS.PAYMENT_MADE_DETAILS);
}) })
.finally(() => { .finally(() => {
closeAlert(name); closeAlert(name);

View File

@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Payment receive delete alert. * Payment receive delete alert.
@@ -50,7 +51,7 @@ function PaymentReceiveDeleteAlert({
), ),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('payment-receive-detail-drawer'); closeDrawer(DRAWERS.PAYMENT_RECEIVE_DETAILS);
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -15,6 +15,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Invoice alert. * Invoice alert.
@@ -47,7 +48,7 @@ function NameDeleteAlert({
message: intl.get('the_receipt_has_been_deleted_successfully'), message: intl.get('the_receipt_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('receipt-detail-drawer'); closeDrawer(DRAWERS.RECEIPT_DETAILS);
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -10,6 +10,7 @@ import withAlertStoreConnect from '@/containers/Alert/withAlertStoreConnect';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Refund Vendor transactions delete alert. * Refund Vendor transactions delete alert.
@@ -43,7 +44,7 @@ function RefundVendorCreditDeleteAlert({
), ),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('refund-vendor-detail-drawer'); closeDrawer(DRAWERS.REFUND_VENDOR_CREDIT_DETAILS);
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {

View File

@@ -14,6 +14,7 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { handleDeleteErrors } from '@/containers/Purchases/CreditNotes/CreditNotesLanding/utils'; import { handleDeleteErrors } from '@/containers/Purchases/CreditNotes/CreditNotesLanding/utils';
import { useDeleteVendorCredit } from '@/hooks/query'; import { useDeleteVendorCredit } from '@/hooks/query';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Vendor Credit delete alert. * Vendor Credit delete alert.
@@ -45,7 +46,7 @@ function VendorCreditDeleteAlert({
message: intl.get('vendor_credits.alert.delete_message'), message: intl.get('vendor_credits.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('vendor-credit-detail-drawer'); closeDrawer(DRAWERS.VENDOR_CREDIT_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -16,6 +16,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Vendor delete alert. * Vendor delete alert.
@@ -48,7 +49,7 @@ function VendorDeleteAlert({
message: intl.get('the_vendor_has_been_deleted_successfully'), message: intl.get('the_vendor_has_been_deleted_successfully'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('vendor-detail-drawer'); closeDrawer(DRAWERS.VENDOR_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -14,6 +14,7 @@ import withAlertActions from '@/containers/Alert/withAlertActions';
import withDrawerActions from '@/containers/Drawer/withDrawerActions'; import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
/** /**
* Warehouse transfer delete alert * Warehouse transfer delete alert
@@ -48,7 +49,7 @@ function WarehouseTransferDeleteAlert({
message: intl.get('warehouse_transfer.alert.delete_message'), message: intl.get('warehouse_transfer.alert.delete_message'),
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
closeDrawer('warehouse-transfer-detail-drawer'); closeDrawer(DRAWERS.WAREHOUSE_TRANSFER_DETAILS);
}) })
.catch( .catch(
({ ({

View File

@@ -23,11 +23,11 @@ export const RegisterSchema = Yup.object().shape({
first_name: Yup.string().required().label(intl.get('first_name_')), first_name: Yup.string().required().label(intl.get('first_name_')),
last_name: Yup.string().required().label(intl.get('last_name_')), last_name: Yup.string().required().label(intl.get('last_name_')),
email: Yup.string().email().required().label(intl.get('email')), email: Yup.string().email().required().label(intl.get('email')),
password: Yup.string().min(4).required().label(intl.get('password')), password: Yup.string().min(6).required().label(intl.get('password')),
}); });
export const ResetPasswordSchema = Yup.object().shape({ export const ResetPasswordSchema = Yup.object().shape({
password: Yup.string().min(4).required().label(intl.get('password')), password: Yup.string().min(6).required().label(intl.get('password')),
confirm_password: Yup.string() confirm_password: Yup.string()
.oneOf([Yup.ref('password'), null]) .oneOf([Yup.ref('password'), null])
.required() .required()

View File

@@ -9,6 +9,7 @@ import {
import { Select } from '@blueprintjs/select'; import { Select } from '@blueprintjs/select';
import { Icon } from '@/components'; import { Icon } from '@/components';
import { DRAWERS } from '@/constants/drawers';
export const CashFlowMenuItems = ({ export const CashFlowMenuItems = ({
text, text,
@@ -53,40 +54,40 @@ export const CashFlowMenuItems = ({
export const handleCashFlowTransactionType = (reference, openDrawer) => { export const handleCashFlowTransactionType = (reference, openDrawer) => {
switch (reference.reference_type) { switch (reference.reference_type) {
case 'SaleReceipt': case 'SaleReceipt':
return openDrawer('receipt-detail-drawer', { return openDrawer(DRAWERS.RECEIPT_DETAILS, {
receiptId: reference.reference_id, receiptId: reference.reference_id,
}); });
case 'Journal': case 'Journal':
return openDrawer('journal-drawer', { return openDrawer(DRAWERS.JOURNAL_DETAILS, {
manualJournalId: reference.reference_id, manualJournalId: reference.reference_id,
}); });
case 'Expense': case 'Expense':
return openDrawer('expense-drawer', { return openDrawer(DRAWERS.EXPENSE_DETAILS, {
expenseId: reference.reference_id, expenseId: reference.reference_id,
}); });
case 'PaymentReceive': case 'PaymentReceive':
return openDrawer('payment-receive-detail-drawer', { return openDrawer(DRAWERS.PAYMENT_RECEIVE_DETAILS, {
paymentReceiveId: reference.reference_id, paymentReceiveId: reference.reference_id,
}); });
case 'BillPayment': case 'BillPayment':
return openDrawer('payment-made-detail-drawer', { return openDrawer(DRAWERS.PAYMENT_MADE_DETAILS, {
paymentMadeId: reference.reference_id, paymentMadeId: reference.reference_id,
}); });
case 'RefundCreditNote': case 'RefundCreditNote':
return openDrawer('refund-credit-detail-drawer', { return openDrawer(DRAWERS.REFUND_CREDIT_NOTE_DETAILS, {
refundTransactionId: reference.reference_id, refundTransactionId: reference.reference_id,
}); });
case 'RefundVendorCredit': case 'RefundVendorCredit':
return openDrawer('refund-vendor-detail-drawer', { return openDrawer(DRAWERS.REFUND_VENDOR_CREDIT_DETAILS, {
refundTransactionId: reference.reference_id, refundTransactionId: reference.reference_id,
}); });
case 'InventoryAdjustment': case 'InventoryAdjustment':
return openDrawer('inventory-adjustment-drawer', { return openDrawer(DRAWERS.INVENTORY_ADJUSTMENT_DETAILS, {
inventoryId: reference.reference_id, inventoryId: reference.reference_id,
}); });
default: default:
return openDrawer('cashflow-transaction-drawer', { return openDrawer(DRAWERS.CASHFLOW_TRNASACTION_DETAILS, {
referenceId: reference.reference_id, referenceId: reference.reference_id,
}); });
} }

View File

@@ -28,6 +28,7 @@ import withDialogActions from '@/containers/Dialog/withDialogActions';
import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils'; import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';
import { safeCallback } from '@/utils'; import { safeCallback } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
const CASHFLOW_SKELETON_N = 4; const CASHFLOW_SKELETON_N = 4;
@@ -63,7 +64,7 @@ function CashflowBankAccount({
}) { }) {
// Handle view detail account. // Handle view detail account.
const handleViewClick = () => { const handleViewClick = () => {
openDrawer('account-drawer', { accountId: account.id }); openDrawer(DRAWERS.ACCOUNT_DETAILS, { accountId: account.id });
}; };
// Handle delete action account. // Handle delete action account.
const handleDeleteClick = () => { const handleDeleteClick = () => {

View File

@@ -1,18 +1,22 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React, { useMemo } from 'react';
import { useFormikContext } from 'formik';
import OwnerContributionFormFields from './OwnerContribution/OwnerContributionFormFields'; import OwnerContributionFormFields from './OwnerContribution/OwnerContributionFormFields';
import OtherIncomeFormFields from './OtherIncome/OtherIncomeFormFields'; import OtherIncomeFormFields from './OtherIncome/OtherIncomeFormFields';
import TransferFromAccountFormFields from './TransferFromAccount/TransferFromAccountFormFields'; import TransferFromAccountFormFields from './TransferFromAccount/TransferFromAccountFormFields';
import { MoneyInFieldsProvider } from './MoneyInFieldsProvider';
/** /**
* * Money-in dialog content.
* @param param0 * Switches between fields based on the given transaction type.
* @returns * @returns {JSX.Element}
*/ */
export default function MoneyInContentFields({ accountType }) { export default function MoneyInContentFields() {
const handleTransactionType = () => { const { values } = useFormikContext();
switch (accountType) {
const transactionFields = useMemo(() => {
switch (values.transaction_type) {
case 'owner_contribution': case 'owner_contribution':
return <OwnerContributionFormFields />; return <OwnerContributionFormFields />;
@@ -24,6 +28,10 @@ export default function MoneyInContentFields({ accountType }) {
default: default:
break; break;
} }
}; }, [values.transaction_type]);
return <React.Fragment>{handleTransactionType()}</React.Fragment>;
// Cannot continue if transaction type or account is not selected.
if (!values.transaction_type || !values.cashflow_account_id) return null;
return <MoneyInFieldsProvider>{transactionFields}</MoneyInFieldsProvider>;
} }

View File

@@ -1,6 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { MoneyInDialogProvider } from './MoneyInDialogProvider'; import { MoneyInDialogProvider } from './MoneyInDialogProvider';
import MoneyInForm from './MoneyInForm'; import MoneyInForm from './MoneyInForm';

Some files were not shown because too many files have changed in this diff Show More