From adac2386bbe695a22014529b127891154327e93e Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Sun, 7 Feb 2021 08:10:21 +0200 Subject: [PATCH] refactoring: migrating to react-query to manage service-side state. --- client/package.json | 2 +- client/src/common/accountTypes.js | 223 ++++++++++++ client/src/components/App.js | 21 +- client/src/components/CategoriesSelectList.js | 4 +- client/src/components/ContextMenu.tsx | 131 +++++++ .../Dashboard/DashboardViewsTabs.js | 10 +- .../src/components/Dashboard/PrivatePages.js | 5 +- client/src/components/DataTable.js | 4 + .../src/components/Datatable/TableHeader.js | 18 +- .../Datatable/TableHeaderSkeleton.js | 42 +++ client/src/components/Datatable/TableRows.js | 2 +- .../components/Datatable/TableSkeletonRows.js | 44 +++ client/src/components/DialogsContainer.js | 6 +- client/src/components/Skeleton.js | 19 ++ client/src/components/index.js | 4 +- client/src/config/sidebarMenu.js | 3 +- .../Accounting/MakeJournalEntriesField.js | 1 - .../Accounting/MakeJournalEntriesForm.js | 109 ++---- .../MakeJournalEntriesHeaderFields.js | 18 +- .../Accounting/MakeJournalEntriesPage.js | 72 +--- .../Accounting/MakeJournalEntriesTable.js | 27 +- .../MakeJournalFormFloatingActions.js | 65 ++-- .../Accounting/MakeJournalNumberWatcher.js | 12 +- .../Accounting/MakeJournalProvider.js | 87 +++++ .../Accounting/ManualJournalActionsBar.js | 59 +--- .../Accounting/ManualJournalsAlerts.js | 15 + .../Accounting/ManualJournalsDataTable.js | 139 +++----- .../Accounting/ManualJournalsList.js | 258 +------------- .../Accounting/ManualJournalsListProvider.js | 37 ++ .../Accounting/ManualJournalsViewTabs.js | 51 +-- .../src/containers/Accounting/components.js | 36 +- .../containers/Accounts/AccountActionsMenu.js | 30 ++ .../containers/Accounts/AccountsActionsBar.js | 89 ++--- .../src/containers/Accounts/AccountsChart.js | 78 +---- .../Accounts/AccountsChartProvider.js | 51 +++ .../containers/Accounts/AccountsDataTable.js | 120 ++----- .../containers/Accounts/AccountsViewPage.js | 60 ++-- .../containers/Accounts/AccountsViewsTabs.js | 75 ++-- client/src/containers/Accounts/components.js | 26 +- .../Accounts/withAccountsTableActions.js | 4 +- .../containers/Alerts/AccountActivateAlert.js | 39 +-- .../containers/Alerts/AccountDeleteAlert.js | 43 +-- .../Alerts/AccountInactivateAlert.js | 45 ++- .../Alerts/Bills/BillDeleteAlert.js | 70 ++++ .../containers/Alerts/Bills/BillOpenAlert.js | 69 ++++ .../Alerts/Customers/CustomerDeleteAlert.js | 13 +- .../Alerts/Estimates/EstimateApproveAlert.js | 19 +- .../Alerts/Estimates/EstimateDeleteAlert.js | 17 +- .../Estimates/EstimateDeliveredAlert.js | 15 +- .../Alerts/Estimates/EstimateRejectAlert.js | 14 +- .../Alerts/Expenses/ExpenseBulkDeleteAlert.js | 66 ++++ .../Alerts/Expenses/ExpenseDeleteAlert.js | 71 ++++ .../Alerts/Expenses/ExpensePublishAlert.js | 64 ++++ .../Alerts/Invoices/InvoiceDeleteAlert.js | 21 +- .../Alerts/Invoices/InvoiceDeliverAlert.js | 24 +- .../Items/InventoryAdjustmentDeleteAlert.js | 23 +- .../Alerts/Items/ItemActivateAlert.js | 21 +- .../Alerts/Items/ItemBulkDeleteAlert.js | 3 +- .../Items/ItemCategoryBulkDeleteAlert.js | 3 +- .../Alerts/Items/ItemCategoryDeleteAlert.js | 22 +- .../Alerts/Items/ItemDeleteAlert.js | 15 +- .../Alerts/Items/ItemInactivateAlert.js | 19 +- .../ManualJournals/JournalBulkDeleteAlert.js | 46 +++ .../ManualJournals/JournalDeleteAlert.js | 68 ++++ .../ManualJournals/JournalPublishAlert.js | 73 ++++ .../PaymentMades/PaymentMadeDeleteAlert.js | 72 ++++ .../PaymentReceiveDeleteAlert.js | 24 +- .../Alerts/Receipts/ReceiptCloseAlert.js | 23 +- .../Alerts/Receipts/ReceiptDeleteAlert.js | 27 +- .../Alerts/Vendors/VendorDeleteAlert.js | 24 +- .../Customers/CustomerActionsBar.js | 32 +- .../Customers/CustomerFinancialPanel.js | 24 +- .../Customers/CustomerFloatingActions.js | 31 +- .../src/containers/Customers/CustomerForm.js | 131 ++----- .../containers/Customers/CustomerFormPage.js | 66 +--- .../Customers/CustomerFormProvider.js | 65 ++++ .../src/containers/Customers/CustomerTable.js | 87 ++--- .../src/containers/Customers/CustomersList.js | 45 +-- .../Customers/CustomersListProvider.js | 41 +++ .../src/containers/Customers/CustomersTabs.js | 4 +- .../containers/Customers/CustomersViewPage.js | 6 +- .../Customers/CustomersViewsTabs.js | 41 +-- .../AccountFormDialogContent.js | 87 +++-- .../AccountFormDialogFields.js | 4 +- .../DecrementAdjustmentFields.js | 7 + .../IncrementAdjustmentFields.js | 8 +- .../InventoryAdjustmentFloatingActions.js | 44 ++- .../InventoryAdjustmentForm.js | 90 +++++ .../InventoryAdjustmentFormContent.js | 16 + .../InventoryAdjustmentFormDialogContent.js | 143 +------- .../InventoryAdjustmentFormDialogFields.js | 27 +- .../InventoryAdjustmentFormProvider.js | 51 +++ .../ItemCategoryDialog/ItemCategoryForm.js | 262 ++++++-------- .../ItemCategoryFormContent.js | 13 + .../ItemCategoryFormDialogContent.js | 163 +-------- .../ItemCategoryFormFields.js | 54 +++ .../ItemCategoryFormFooter.js | 43 +++ .../ItemCategoryProvider.js | 57 ++++ .../Dialogs/ItemCategoryDialog/index.js | 2 +- .../itemCategoryForm.schema.js | 3 - .../Entries/EditableItemsEntriesTable.js | 5 + .../containers/Entries/ItemsEntriesTable.js | 22 +- .../containers/Expenses/ExpenseActionsBar.js | 67 +--- .../containers/Expenses/ExpenseDataTable.js | 130 +++---- .../Expenses/ExpenseFloatingActions.js | 25 +- client/src/containers/Expenses/ExpenseForm.js | 58 ++-- .../containers/Expenses/ExpenseFormEntries.js | 20 +- .../Expenses/ExpenseFormHeaderFields.js | 38 +-- .../containers/Expenses/ExpenseFormPage.js | 55 +-- .../Expenses/ExpenseFormPageProvider.js | 71 ++++ .../containers/Expenses/ExpenseViewTabs.js | 52 +-- .../src/containers/Expenses/ExpensesAlerts.js | 17 + .../src/containers/Expenses/ExpensesList.js | 244 +------------ .../Expenses/ExpensesListProvider.js | 44 +++ .../containers/Expenses/ExpensesViewPage.js | 37 ++ .../ARAgingSummary/ARAgingSummaryProvider.js | 0 .../BalanceSheet/BalanceSheet.js | 43 +-- .../BalanceSheet/BalanceSheetActionsBar.js | 14 +- .../BalanceSheet/BalanceSheetProvider.js | 27 ++ .../BalanceSheet/BalanceSheetTable.js | 64 ++-- .../GeneralLedger/GeneralLedger.js | 44 +-- .../GeneralLedger/GeneralLedgerActionsBar.js | 7 +- .../GeneralLedger/GeneralLedgerProvider.js | 32 ++ .../GeneralLedger/GeneralLedgerTable.js | 69 ++-- .../FinancialStatements/Journal/Journal.js | 36 +- .../Journal/JournalActionsBar.js | 8 +- .../Journal/JournalProvider.js | 31 ++ .../Journal/JournalTable.js | 39 +-- .../ProfitLossSheet/ProfitLossActionsBar.js | 12 +- .../ProfitLossSheet/ProfitLossProvider.js | 28 ++ .../ProfitLossSheet/ProfitLossSheet.js | 52 +-- .../ProfitLossSheet/ProfitLossSheetTable.js | 66 ++-- .../TrialBalanceActionsBar.js | 16 +- .../TrialBalanceSheet/TrialBalanceProvider.js | 30 ++ .../TrialBalanceSheet/TrialBalanceSheet.js | 50 +-- .../TrialBalanceSheetHeader.js | 2 - .../TrialBalanceSheetTable.js | 57 ++-- .../FinancialStatements/reducers.js | 228 +++++++++++++ .../InventoryAdjustmentDataTable.js | 98 ++---- .../InventoryAdjustmentList.js | 47 +++ .../InventoryAdjustmentView.js | 33 ++ .../InventoryAdjustmentsAlerts.js | 10 + .../InventoryAdjustmentsProvider.js | 39 +++ .../InventoryAdjustments/components.js | 137 ++++++++ .../withInventoryAdjustmentActions.js | 0 .../withInventoryAdjustments.js | 0 .../Items/InventoryAdjustmentList.js | 79 ----- .../containers/Items/ItemCategoriesList.js | 88 ----- .../containers/Items/ItemCategoriesTable.js | 174 ---------- client/src/containers/Items/ItemForm.js | 153 ++------- client/src/containers/Items/ItemFormBody.js | 18 +- .../Items/ItemFormFloatingActions.js | 47 ++- .../Items/ItemFormInventorySection.js | 40 +-- client/src/containers/Items/ItemFormPage.js | 81 +---- .../Items/ItemFormPrimarySection.js | 38 +-- .../src/containers/Items/ItemFormProvider.js | 85 +++++ .../src/containers/Items/ItemsActionsBar.js | 70 ++-- client/src/containers/Items/ItemsAlerts.js | 6 - client/src/containers/Items/ItemsDataTable.js | 322 ++++-------------- client/src/containers/Items/ItemsList.js | 80 +---- .../src/containers/Items/ItemsListProvider.js | 63 ++++ client/src/containers/Items/ItemsViewPage.js | 51 ++- client/src/containers/Items/ItemsViewsTabs.js | 49 +-- client/src/containers/Items/components.js | 137 ++++++++ .../ItemsCategories/ItemCategoriesList.js | 45 +++ .../ItemsCategories/ItemCategoriesTable.js | 75 ++++ .../ItemsCategories/ItemCategoriesViewPage.js | 47 +++ .../ItemsCategories/ItemsCategoriesAlerts.js | 12 + .../ItemsCategoriesProvider.js | 35 ++ .../ItemsCategoryActionsBar.js | 36 +- .../containers/ItemsCategories/components.js | 54 +++ .../withItemCategories.js | 0 .../withItemCategoriesActions.js | 0 .../withItemCategoryDetail.js | 0 .../Purchases/Bill/BillFloatingActions.js | 63 ++-- .../src/containers/Purchases/Bill/BillForm.js | 112 ++---- .../containers/Purchases/Bill/BillFormBody.js | 4 + .../Purchases/Bill/BillFormFooter.js | 11 +- .../Purchases/Bill/BillFormHeaderFields.js | 18 +- .../containers/Purchases/Bill/BillFormPage.js | 80 +---- .../Purchases/Bill/BillFormProvider.js | 81 +++++ .../containers/Purchases/Bill/BillViewTabs.js | 65 +--- .../{BillActionsBar.js => BillsActionsBar.js} | 72 +--- .../containers/Purchases/Bill/BillsAlerts.js | 12 + .../Purchases/Bill/BillsDataTable.js | 50 ++- .../containers/Purchases/Bill/BillsList.js | 178 +--------- .../Purchases/Bill/BillsListProvider.js | 52 +++ .../Purchases/Bill/BillsViewPage.js | 49 +++ .../PaymentMades/PaymentMadeActionsBar.js | 79 +---- .../Purchases/PaymentMades/PaymentMadeList.js | 149 +------- .../PaymentMades/PaymentMadeViewTabs.js | 79 +---- .../PaymentMades/PaymentMadesAlerts.js | 10 + .../PaymentMades/PaymentMadesListProvider.js | 58 ++++ .../PaymentMades/PaymentMadesView.js | 38 +++ .../PaymentMades/PaymentMdesListProvider.js | 52 +++ .../Sales/Estimate/EstiamtesViewPage.js | 84 +++++ .../Sales/Estimate/EstimateActionsBar.js | 64 +--- .../containers/Sales/Estimate/EstimateForm.js | 2 - .../Sales/Estimate/EstimateViewTabs.js | 60 +--- .../Sales/Estimate/EstimatesList.js | 148 +------- .../Sales/Estimate/EstimatesListProvider.js | 52 +++ .../Sales/Invoice/InvoiceActionsBar.js | 74 +--- .../Sales/Invoice/InvoiceFloatingActions.js | 69 ++-- .../containers/Sales/Invoice/InvoiceForm.js | 97 ++---- .../Sales/Invoice/InvoiceFormHeaderFields.js | 15 +- .../Sales/Invoice/InvoiceFormPage.js | 53 +-- .../Sales/Invoice/InvoiceFormProvider.js | 71 ++++ .../Sales/Invoice/InvoiceViewTabs.js | 54 +-- .../containers/Sales/Invoice/InvoicesList.js | 112 +----- .../Sales/Invoice/InvoicesListProvider.js | 52 +++ .../Sales/Invoice/InvoicesViewPage.js | 73 ++++ .../PaymentReceiptsListProvider.js | 52 +++ .../PaymentReceiveFloatingActions.js | 2 +- .../PaymentReceive/PaymentReceiveViewTabs.js | 84 +---- .../PaymentReceive/PaymentReceivesList.js | 89 +---- .../PaymentReceivesListProvider.js | 58 ++++ .../PaymentReceive/PaymentReceivesViewPage.js | 55 +++ .../Sales/Receipt/ReceiptActionsBar.js | 75 +--- .../containers/Sales/Receipt/ReceiptForm.js | 104 ++---- .../Sales/Receipt/ReceiptFormBody.js | 4 + .../Receipt/ReceiptFormFloatingActions.js | 62 ++-- .../Sales/Receipt/ReceiptFormHeaderFields.js | 25 +- .../Sales/Receipt/ReceiptFormPage.js | 89 +---- .../Sales/Receipt/ReceiptFormProvider.js | 85 +++++ .../Sales/Receipt/ReceiptViewTabs.js | 66 +--- .../containers/Sales/Receipt/ReceiptsList.js | 105 +----- .../Sales/Receipt/ReceiptsListProvider.js | 48 +++ .../Sales/Receipt/ReceiptsViewPage.js | 66 ++++ .../containers/Vendors/VendorActionsBar.js | 46 +-- .../Vendors/VendorFinanicalPanelTab.js | 25 +- .../Vendors/VendorFloatingActions.js | 50 +-- client/src/containers/Vendors/VendorForm.js | 78 ++--- .../Vendors/VendorFormAfterPrimarySection.js | 2 - .../src/containers/Vendors/VendorFormPage.js | 65 +--- .../containers/Vendors/VendorFormProvider.js | 61 ++++ .../src/containers/Vendors/VendorViewsTabs.js | 46 +-- client/src/containers/Vendors/VendorsList.js | 54 +-- .../containers/Vendors/VendorsListProvider.js | 39 +++ client/src/containers/Vendors/VendorsTable.js | 103 ++---- client/src/containers/Vendors/VendorsTabs.js | 4 +- client/src/hooks/index.js | 11 +- client/src/hooks/query/accounts.js | 132 +++++++ client/src/hooks/query/bills.js | 115 +++++++ client/src/hooks/query/currencies.js | 41 +++ client/src/hooks/query/customers.js | 72 ++++ client/src/hooks/query/estimates.js | 129 +++++++ client/src/hooks/query/expenses.js | 42 +++ client/src/hooks/query/financialReports.js | 147 ++++++++ client/src/hooks/query/index.js | 19 ++ .../src/hooks/query/inventoryAdjustments.js | 65 ++++ client/src/hooks/query/invoices.js | 115 +++++++ client/src/hooks/query/items.js | 116 +++++++ client/src/hooks/query/itemsCategories.js | 94 +++++ client/src/hooks/query/manualJournals.js | 87 +++++ client/src/hooks/query/paymentMades.js | 91 +++++ client/src/hooks/query/paymentReceives.js | 91 +++++ client/src/hooks/query/receipts.js | 114 +++++++ client/src/hooks/query/settings.js | 45 +++ client/src/hooks/query/vendors.js | 81 +++++ client/src/hooks/query/views.js | 51 +++ client/src/hooks/state/dashboard.js | 10 + client/src/hooks/state/index.js | 1 + client/src/index.js | 8 - client/src/lang/en/index.js | 3 +- client/src/routes/dashboard.js | 4 +- client/src/store/accounts/accounts.actions.js | 6 +- client/src/store/accounts/accounts.reducer.js | 12 +- client/src/store/accounts/accounts.types.js | 1 - .../src/store/dashboard/dashboard.actions.js | 7 + .../financialStatements.mappers.js | 112 +----- client/src/store/queryReducers.js | 6 +- .../style/components/DataTable/DataTable.scss | 17 + client/src/style/components/PageForm.scss | 15 + client/src/style/components/Skeleton.scss | 26 ++ .../style/containers/Dashboard/Sidebar.scss | 6 +- .../src/style/pages/Dashboard/Dashboard.scss | 4 +- .../FinancialStatements/ProfitLossSheet.scss | 2 +- .../ItemCategory/ItemCategoryDialog.scss | 7 + client/src/style/pages/Items/PageForm.scss | 4 + client/src/utils.js | 37 +- server/src/data/AccountTypes.ts | 7 +- .../core/20200810121808_seed_views_roles.js | 10 +- server/src/models/Account.js | 18 +- .../src/services/Expenses/ExpensesService.ts | 4 +- 284 files changed, 8255 insertions(+), 6610 deletions(-) create mode 100644 client/src/common/accountTypes.js create mode 100644 client/src/components/ContextMenu.tsx create mode 100644 client/src/components/Datatable/TableHeaderSkeleton.js create mode 100644 client/src/components/Datatable/TableSkeletonRows.js create mode 100644 client/src/components/Skeleton.js create mode 100644 client/src/containers/Accounting/MakeJournalProvider.js create mode 100644 client/src/containers/Accounting/ManualJournalsAlerts.js create mode 100644 client/src/containers/Accounting/ManualJournalsListProvider.js create mode 100644 client/src/containers/Accounts/AccountActionsMenu.js create mode 100644 client/src/containers/Accounts/AccountsChartProvider.js create mode 100644 client/src/containers/Alerts/Bills/BillDeleteAlert.js create mode 100644 client/src/containers/Alerts/Bills/BillOpenAlert.js create mode 100644 client/src/containers/Alerts/Expenses/ExpenseBulkDeleteAlert.js create mode 100644 client/src/containers/Alerts/Expenses/ExpenseDeleteAlert.js create mode 100644 client/src/containers/Alerts/Expenses/ExpensePublishAlert.js create mode 100644 client/src/containers/Alerts/ManualJournals/JournalBulkDeleteAlert.js create mode 100644 client/src/containers/Alerts/ManualJournals/JournalDeleteAlert.js create mode 100644 client/src/containers/Alerts/ManualJournals/JournalPublishAlert.js create mode 100644 client/src/containers/Alerts/PaymentMades/PaymentMadeDeleteAlert.js create mode 100644 client/src/containers/Customers/CustomerFormProvider.js create mode 100644 client/src/containers/Customers/CustomersListProvider.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormContent.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormProvider.js create mode 100644 client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryFormContent.js create mode 100644 client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryFormFields.js create mode 100644 client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryFormFooter.js create mode 100644 client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryProvider.js create mode 100644 client/src/containers/Expenses/ExpenseFormPageProvider.js create mode 100644 client/src/containers/Expenses/ExpensesAlerts.js create mode 100644 client/src/containers/Expenses/ExpensesListProvider.js create mode 100644 client/src/containers/Expenses/ExpensesViewPage.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryProvider.js create mode 100644 client/src/containers/FinancialStatements/BalanceSheet/BalanceSheetProvider.js create mode 100644 client/src/containers/FinancialStatements/GeneralLedger/GeneralLedgerProvider.js create mode 100644 client/src/containers/FinancialStatements/Journal/JournalProvider.js create mode 100644 client/src/containers/FinancialStatements/ProfitLossSheet/ProfitLossProvider.js create mode 100644 client/src/containers/FinancialStatements/TrialBalanceSheet/TrialBalanceProvider.js create mode 100644 client/src/containers/FinancialStatements/reducers.js rename client/src/containers/{Items => InventoryAdjustments}/InventoryAdjustmentDataTable.js (65%) create mode 100644 client/src/containers/InventoryAdjustments/InventoryAdjustmentList.js create mode 100644 client/src/containers/InventoryAdjustments/InventoryAdjustmentView.js create mode 100644 client/src/containers/InventoryAdjustments/InventoryAdjustmentsAlerts.js create mode 100644 client/src/containers/InventoryAdjustments/InventoryAdjustmentsProvider.js create mode 100644 client/src/containers/InventoryAdjustments/components.js rename client/src/containers/{Items => InventoryAdjustments}/withInventoryAdjustmentActions.js (100%) rename client/src/containers/{Items => InventoryAdjustments}/withInventoryAdjustments.js (100%) delete mode 100644 client/src/containers/Items/InventoryAdjustmentList.js delete mode 100644 client/src/containers/Items/ItemCategoriesList.js delete mode 100644 client/src/containers/Items/ItemCategoriesTable.js create mode 100644 client/src/containers/Items/ItemFormProvider.js create mode 100644 client/src/containers/Items/ItemsListProvider.js create mode 100644 client/src/containers/Items/components.js create mode 100644 client/src/containers/ItemsCategories/ItemCategoriesList.js create mode 100644 client/src/containers/ItemsCategories/ItemCategoriesTable.js create mode 100644 client/src/containers/ItemsCategories/ItemCategoriesViewPage.js create mode 100644 client/src/containers/ItemsCategories/ItemsCategoriesAlerts.js create mode 100644 client/src/containers/ItemsCategories/ItemsCategoriesProvider.js rename client/src/containers/{Items => ItemsCategories}/ItemsCategoryActionsBar.js (81%) create mode 100644 client/src/containers/ItemsCategories/components.js rename client/src/containers/{Items => ItemsCategories}/withItemCategories.js (100%) rename client/src/containers/{Items => ItemsCategories}/withItemCategoriesActions.js (100%) rename client/src/containers/{Items => ItemsCategories}/withItemCategoryDetail.js (100%) create mode 100644 client/src/containers/Purchases/Bill/BillFormProvider.js rename client/src/containers/Purchases/Bill/{BillActionsBar.js => BillsActionsBar.js} (64%) create mode 100644 client/src/containers/Purchases/Bill/BillsAlerts.js create mode 100644 client/src/containers/Purchases/Bill/BillsListProvider.js create mode 100644 client/src/containers/Purchases/Bill/BillsViewPage.js create mode 100644 client/src/containers/Purchases/PaymentMades/PaymentMadesAlerts.js create mode 100644 client/src/containers/Purchases/PaymentMades/PaymentMadesListProvider.js create mode 100644 client/src/containers/Purchases/PaymentMades/PaymentMadesView.js create mode 100644 client/src/containers/Purchases/PaymentMades/PaymentMdesListProvider.js create mode 100644 client/src/containers/Sales/Estimate/EstiamtesViewPage.js create mode 100644 client/src/containers/Sales/Estimate/EstimatesListProvider.js create mode 100644 client/src/containers/Sales/Invoice/InvoiceFormProvider.js create mode 100644 client/src/containers/Sales/Invoice/InvoicesListProvider.js create mode 100644 client/src/containers/Sales/Invoice/InvoicesViewPage.js create mode 100644 client/src/containers/Sales/PaymentReceive/PaymentReceiptsListProvider.js create mode 100644 client/src/containers/Sales/PaymentReceive/PaymentReceivesListProvider.js create mode 100644 client/src/containers/Sales/PaymentReceive/PaymentReceivesViewPage.js create mode 100644 client/src/containers/Sales/Receipt/ReceiptFormProvider.js create mode 100644 client/src/containers/Sales/Receipt/ReceiptsListProvider.js create mode 100644 client/src/containers/Sales/Receipt/ReceiptsViewPage.js create mode 100644 client/src/containers/Vendors/VendorFormProvider.js create mode 100644 client/src/containers/Vendors/VendorsListProvider.js create mode 100644 client/src/hooks/query/accounts.js create mode 100644 client/src/hooks/query/bills.js create mode 100644 client/src/hooks/query/currencies.js create mode 100644 client/src/hooks/query/customers.js create mode 100644 client/src/hooks/query/estimates.js create mode 100644 client/src/hooks/query/expenses.js create mode 100644 client/src/hooks/query/financialReports.js create mode 100644 client/src/hooks/query/index.js create mode 100644 client/src/hooks/query/inventoryAdjustments.js create mode 100644 client/src/hooks/query/invoices.js create mode 100644 client/src/hooks/query/items.js create mode 100644 client/src/hooks/query/itemsCategories.js create mode 100644 client/src/hooks/query/manualJournals.js create mode 100644 client/src/hooks/query/paymentMades.js create mode 100644 client/src/hooks/query/paymentReceives.js create mode 100644 client/src/hooks/query/receipts.js create mode 100644 client/src/hooks/query/settings.js create mode 100644 client/src/hooks/query/vendors.js create mode 100644 client/src/hooks/query/views.js create mode 100644 client/src/hooks/state/dashboard.js create mode 100644 client/src/hooks/state/index.js create mode 100644 client/src/style/components/Skeleton.scss diff --git a/client/package.json b/client/package.json index 87266a85b..59cd4cede 100644 --- a/client/package.json +++ b/client/package.json @@ -77,7 +77,7 @@ "react-hotkeys-hook": "^3.0.3", "react-intl": "^3.12.0", "react-loadable": "^5.5.0", - "react-query": "^2.4.6", + "react-query": "^3.6.0", "react-redux": "^7.1.3", "react-router-breadcrumbs-hoc": "^3.2.10", "react-router-dom": "^5.2.0", diff --git a/client/src/common/accountTypes.js b/client/src/common/accountTypes.js new file mode 100644 index 000000000..3e84a1e7d --- /dev/null +++ b/client/src/common/accountTypes.js @@ -0,0 +1,223 @@ +export const ACCOUNT_TYPE = { + CASH: 'cash', + BANK: 'bank', + ACCOUNTS_RECEIVABLE: 'accounts-receivable', + INVENTORY: 'inventory', + OTHER_CURRENT_ASSET: 'other-ACCOUNT_PARENT_TYPE.CURRENT_ASSET', + FIXED_ASSET: 'fixed-asset', + NON_CURRENT_ASSET: 'non-ACCOUNT_PARENT_TYPE.CURRENT_ASSET', + + ACCOUNTS_PAYABLE: 'accounts-payable', + CREDIT_CARD: 'credit-card', + TAX_PAYABLE: 'tax-payable', + OTHER_CURRENT_LIABILITY: 'other-current-liability', + LOGN_TERM_LIABILITY: 'long-term-liability', + NON_CURRENT_LIABILITY: 'non-current-liability', + + EQUITY: 'equity', + INCOME: 'income', + OTHER_INCOME: 'other-income', + COST_OF_GOODS_SOLD: 'cost-of-goods-sold', + EXPENSE: 'expense', + OTHER_EXPENSE: 'other-expense', +}; + +export const ACCOUNT_PARENT_TYPE = { + CURRENT_ASSET: 'current-asset', + FIXED_ASSET: 'fixed-asset', + NON_CURRENT_ASSET: 'non-ACCOUNT_PARENT_TYPE.CURRENT_ASSET', + + CURRENT_LIABILITY: 'current-liability', + LOGN_TERM_LIABILITY: 'long-term-liability', + NON_CURRENT_LIABILITY: 'non-current-liability', + + EQUITY: 'equity', + EXPENSE: 'expense', + INCOME: 'income', +}; + +export const ACCOUNT_ROOT_TYPE = { + ASSET: 'asset', + LIABILITY: 'liability', + EQUITY: 'equity', + EXPENSE: 'expene', + INCOME: 'income', +}; + +export const ACCOUNT_NORMAL = { + CREDIT: 'credit', + DEBIT: 'debit', +}; +export const ACCOUNT_TYPES = [ + { + label: 'Cash', + key: ACCOUNT_TYPE.CASH, + normal: ACCOUNT_NORMAL.DEBIT, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_ASSET, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Bank', + key: ACCOUNT_TYPE.BANK, + normal: ACCOUNT_NORMAL.DEBIT, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_ASSET, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Accounts Receivable', + key: ACCOUNT_TYPE.ACCOUNTS_RECEIVABLE, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Inventory', + key: ACCOUNT_TYPE.INVENTORY, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Other Current Asset', + key: ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Fixed Asset', + key: ACCOUNT_TYPE.FIXED_ASSET, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + parentType: ACCOUNT_PARENT_TYPE.FIXED_ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Non-Current Asset', + key: ACCOUNT_TYPE.NON_CURRENT_ASSET, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.ASSET, + parentType: ACCOUNT_PARENT_TYPE.FIXED_ASSET, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Accounts Payable', + key: ACCOUNT_TYPE.ACCOUNTS_PAYABLE, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.LIABILITY, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_LIABILITY, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Credit Card', + key: ACCOUNT_TYPE.CREDIT_CARD, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.LIABILITY, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_LIABILITY, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Tax Payable', + key: ACCOUNT_TYPE.TAX_PAYABLE, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.LIABILITY, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_LIABILITY, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Other Current Liability', + key: ACCOUNT_TYPE.OTHER_CURRENT_LIABILITY, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.LIABILITY, + parentType: ACCOUNT_PARENT_TYPE.CURRENT_LIABILITY, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Long Term Liability', + key: ACCOUNT_TYPE.LOGN_TERM_LIABILITY, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.LIABILITY, + parentType: ACCOUNT_PARENT_TYPE.LOGN_TERM_LIABILITY, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Non-Current Liability', + key: ACCOUNT_TYPE.NON_CURRENT_LIABILITY, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.LIABILITY, + parentType: ACCOUNT_PARENT_TYPE.NON_CURRENT_LIABILITY, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Equity', + key: ACCOUNT_TYPE.EQUITY, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.EQUITY, + parentType: ACCOUNT_PARENT_TYPE.EQUITY, + balanceSheet: true, + incomeSheet: false, + }, + { + label: 'Income', + key: ACCOUNT_TYPE.INCOME, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.INCOME, + parentType: ACCOUNT_PARENT_TYPE.INCOME, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Other Income', + key: ACCOUNT_TYPE.OTHER_INCOME, + normal: ACCOUNT_NORMAL.CREDIT, + rootType: ACCOUNT_ROOT_TYPE.INCOME, + parentType: ACCOUNT_PARENT_TYPE.INCOME, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Cost of Goods Sold', + key: ACCOUNT_TYPE.COST_OF_GOODS_SOLD, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.EXPENSE, + parentType: ACCOUNT_PARENT_TYPE.EXPENSE, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Expense', + key: ACCOUNT_TYPE.EXPENSE, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.EXPENSE, + parentType: ACCOUNT_PARENT_TYPE.EXPENSE, + balanceSheet: false, + incomeSheet: true, + }, + { + label: 'Other Expense', + key: ACCOUNT_TYPE.OTHER_EXPENSE, + normal: ACCOUNT_NORMAL.DEBIT, + rootType: ACCOUNT_ROOT_TYPE.EXPENSE, + parentType: ACCOUNT_PARENT_TYPE.EXPENSE, + balanceSheet: false, + incomeSheet: true, + }, +]; diff --git a/client/src/components/App.js b/client/src/components/App.js index 00df2b8aa..435d11a9b 100644 --- a/client/src/components/App.js +++ b/client/src/components/App.js @@ -2,9 +2,7 @@ import React from 'react'; import { RawIntlProvider } from 'react-intl'; import { Router, Switch, Route } from 'react-router'; import { createBrowserHistory } from 'history'; -import { ReactQueryConfigProvider } from 'react-query'; -import { ReactQueryDevtools } from 'react-query-devtools'; - +import { QueryClientProvider, QueryClient } from 'react-query'; import 'style/App.scss'; import PrivateRoute from 'components/Guards/PrivateRoute'; @@ -17,14 +15,18 @@ function App({ locale }) { const history = createBrowserHistory(); const queryConfig = { - queries: { - refetchOnWindowFocus: false, + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, }, }; + const queryClient = new QueryClient(queryConfig); + return ( -
- + +
@@ -38,9 +40,8 @@ function App({ locale }) { - - -
+
+
); } diff --git a/client/src/components/CategoriesSelectList.js b/client/src/components/CategoriesSelectList.js index 52bf07a14..1345d1f6c 100644 --- a/client/src/components/CategoriesSelectList.js +++ b/client/src/components/CategoriesSelectList.js @@ -7,7 +7,7 @@ import classNames from 'classnames'; import { CLASSES } from 'common/classes'; export default function CategoriesSelectList({ - categoriesList, + categories, selecetedCategoryId, defaultSelectText = , onCategorySelected, @@ -41,7 +41,7 @@ export default function CategoriesSelectList({ return ( void; +} + +const POPPER_MODIFIERS = { + preventOverflow: { boundariesElement: "viewport" }, +}; +const TRANSITION_DURATION = 100; + +// type IContextMenuProps = IOverlayLifecycleProps; + +/* istanbul ignore next */ + +export default class ContextMenu extends React.PureComponent { + public state: IContextMenuState = { + isDarkTheme: false, + isOpen: false, + }; + + public render() { + // prevent right-clicking in a context menu + const content =
{this.state.menu}
; + const popoverClassName = {}; + + // HACKHACK: workaround until we have access to Popper#scheduleUpdate(). + // https://github.com/palantir/blueprint/issues/692 + // Generate key based on offset so a new Popover instance is created + // when offset changes, to force recomputing position. + const key = this.state.offset === undefined ? "" : `${this.state.offset.left}x${this.state.offset.top}`; + + // wrap the popover in a positioned div to make sure it is properly + // offset on the screen. + return ( +
+ } + transitionDuration={TRANSITION_DURATION} + /> +
+ ); + + } + + public show(menu: JSX.Element, offset: IOffset, onClose?: () => void, isDarkTheme = false) { + this.setState({ isOpen: true, menu, offset, onClose, isDarkTheme }); + } + + public hide() { + this.state.onClose?.(); + this.setState({ isOpen: false, onClose: undefined }); + } + + private cancelContextMenu = (e: React.SyntheticEvent) => e.preventDefault(); + + private handleBackdropContextMenu = (e: React.MouseEvent) => { + // React function to remove from the event pool, useful when using a event within a callback + e.persist(); + e.preventDefault(); + // wait for backdrop to disappear so we can find the "real" element at event coordinates. + // timeout duration is equivalent to transition duration so we know it's animated out. + setTimeout(() => { + // retrigger context menu event at the element beneath the backdrop. + // if it has a `contextmenu` event handler then it'll be invoked. + // if it doesn't, no native menu will show (at least on OSX) :( + const newTarget = document.elementFromPoint(e.clientX, e.clientY); + const { view, ...newEventInit } = e; + newTarget?.dispatchEvent(new MouseEvent("contextmenu", newEventInit)); + }, TRANSITION_DURATION); + }; + + private handlePopoverInteraction = (nextOpenState: boolean) => { + if (!nextOpenState) { + // delay the actual hiding till the event queue clears + // to avoid flicker of opening twice + this.hide(); + } + }; +} \ No newline at end of file diff --git a/client/src/components/Dashboard/DashboardViewsTabs.js b/client/src/components/Dashboard/DashboardViewsTabs.js index e07ebcf01..92fbfcb85 100644 --- a/client/src/components/Dashboard/DashboardViewsTabs.js +++ b/client/src/components/Dashboard/DashboardViewsTabs.js @@ -5,9 +5,11 @@ import { Button, Tabs, Tab, Tooltip, Position } from '@blueprintjs/core'; import { debounce } from 'lodash'; import { useHistory } from 'react-router'; import { If, Icon } from 'components'; +import { saveInvoke } from 'utils'; export default function DashboardViewsTabs({ initialViewId = 0, + viewId, tabs, defaultTabText = , allTab = true, @@ -26,16 +28,16 @@ export default function DashboardViewsTabs({ }; const handleTabClick = (viewId) => { - onTabClick && onTabClick(viewId); + saveInvoke(onTabClick, viewId); }; const mappedTabs = useMemo( () => tabs.map((tab) => ({ ...tab, onTabClick: handleTabClick })), - [tabs], + [tabs, handleTabClick], ); const handleViewLinkClick = () => { - onNewViewTabClick && onNewViewTabClick(); + saveInvoke(onNewViewTabClick); }; const debounceChangeHistory = useRef( @@ -49,7 +51,7 @@ export default function DashboardViewsTabs({ debounceChangeHistory.current(`/${resourceName}/${toPath}`); setCurrentView(viewId); - onChange && onChange(viewId); + saveInvoke(onChange, viewId); }; return ( diff --git a/client/src/components/Dashboard/PrivatePages.js b/client/src/components/Dashboard/PrivatePages.js index 55c981191..1534d4078 100644 --- a/client/src/components/Dashboard/PrivatePages.js +++ b/client/src/components/Dashboard/PrivatePages.js @@ -26,15 +26,14 @@ function DashboardPrivatePages({ // #withSubscriptionsActions requestFetchSubscriptions, }) { - // Fetch all user's organizatins. + // Fetches all user's organizatins. const fetchOrganizations = useQuery( ['organizations'], () => requestAllOrganizations(), ); - // Fetchs organization subscriptions. + // Fetches organization subscriptions. const fetchSuscriptions = useQuery( ['susbcriptions'], () => requestFetchSubscriptions(), - { enabled: fetchOrganizations.data }, ) return ( diff --git a/client/src/components/DataTable.js b/client/src/components/DataTable.js index 2abbe1047..b6d07e4a1 100644 --- a/client/src/components/DataTable.js +++ b/client/src/components/DataTable.js @@ -83,6 +83,7 @@ export default function DataTable(props) { minWidth: selectionColumnWidth, width: selectionColumnWidth, maxWidth: selectionColumnWidth, + skeletonWidthMin: 100, // The header can use the table's getToggleAllRowsSelectedProps method // to render a checkbox Header: TableIndeterminateCheckboxHeader, @@ -198,4 +199,7 @@ DataTable.defaultProps = { TableTBodyRenderer: TableTBody, TablePaginationRenderer: TablePagination, TableNoResultsRowRenderer: TableNoResultsRow, + + noResults: 'There is no results in the table.', + payload: {}, }; \ No newline at end of file diff --git a/client/src/components/Datatable/TableHeader.js b/client/src/components/Datatable/TableHeader.js index 91995b3c5..145296386 100644 --- a/client/src/components/Datatable/TableHeader.js +++ b/client/src/components/Datatable/TableHeader.js @@ -27,11 +27,13 @@ function TableHeaderCell({ column, index }) { -
+
{column.render('Header')} @@ -74,9 +76,13 @@ function TableHeaderGroup({ headerGroup }) { */ export default function TableHeader() { const { - table: { headerGroups }, + table: { headerGroups, page }, + props: { TableHeaderSkeletonRenderer, headerLoading }, } = useContext(TableContext); + if (headerLoading && TableHeaderSkeletonRenderer) { + return ; + } return (
diff --git a/client/src/components/Datatable/TableHeaderSkeleton.js b/client/src/components/Datatable/TableHeaderSkeleton.js new file mode 100644 index 000000000..e5f2baba7 --- /dev/null +++ b/client/src/components/Datatable/TableHeaderSkeleton.js @@ -0,0 +1,42 @@ +import React, { useContext } from 'react'; +import TableContext from './TableContext'; +import { Skeleton } from 'components'; + +function TableHeaderCell({ column }) { + const { skeletonWidthMax = 100, skeletonWidthMin = 40 } = column; + + return ( +
+ +
+ ); +} + +/** + * Table skeleton rows. + */ +export default function TableSkeletonHeader({}) { + const { + table: { headerGroups }, + } = useContext(TableContext); + + return ( +
+ {headerGroups.map((headerGroup) => ( +
+ {headerGroup.headers.map((column) => ( + + ))} +
+ ))} +
+ ); +} diff --git a/client/src/components/Datatable/TableRows.js b/client/src/components/Datatable/TableRows.js index 95c073f60..cd27400f0 100644 --- a/client/src/components/Datatable/TableRows.js +++ b/client/src/components/Datatable/TableRows.js @@ -9,7 +9,7 @@ export default function TableRows() { table: { prepareRow, page }, props: { TableRowRenderer, TableCellRenderer }, } = useContext(TableContext); - + return page.map((row) => { prepareRow(row); return ; diff --git a/client/src/components/Datatable/TableSkeletonRows.js b/client/src/components/Datatable/TableSkeletonRows.js new file mode 100644 index 000000000..cf1d74e89 --- /dev/null +++ b/client/src/components/Datatable/TableSkeletonRows.js @@ -0,0 +1,44 @@ +import React, { useContext } from 'react'; +import TableContext from './TableContext'; +import { Skeleton } from 'components'; + +/** + * Table header cell. + */ +function TableHeaderCell({ column }) { + const { skeletonWidthMax = 100, skeletonWidthMin = 40 } = column; + + return ( +
+ +
+ ); +} + +/** + * Table skeleton rows. + */ +export default function TableSkeletonRows({}) { + const { + table: { headerGroups }, + } = useContext(TableContext); + const skeletonRows = 10; + + return Array.from({ length: skeletonRows }).map(() => { + return headerGroups.map((headerGroup) => ( +
+ {headerGroup.headers.map((column) => ( + + ))} +
+ )); + }); +} diff --git a/client/src/components/DialogsContainer.js b/client/src/components/DialogsContainer.js index b13dbaabf..a84df5e5f 100644 --- a/client/src/components/DialogsContainer.js +++ b/client/src/components/DialogsContainer.js @@ -11,9 +11,11 @@ import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog'; import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog'; import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog'; import InventoryAdjustmentDialog from 'containers/Dialogs/InventoryAdjustmentFormDialog'; - import PaymentViaVoucherDialog from 'containers/Dialogs/PaymentViaVoucherDialog'; +/** + * Dialogs container. + */ export default function DialogsContainer() { return (
@@ -27,7 +29,7 @@ export default function DialogsContainer() { - +
); diff --git a/client/src/components/Skeleton.js b/client/src/components/Skeleton.js new file mode 100644 index 000000000..df6df2c25 --- /dev/null +++ b/client/src/components/Skeleton.js @@ -0,0 +1,19 @@ +import React, { useMemo } from 'react'; +import 'style/components/Skeleton.scss'; + +import { randomNumber } from 'utils'; + +/** + * Skeleton component. + */ +export default function Skeleton({ + Tag = 'span', + minWidth = 40, + maxWidth = 100, +}) { + const randomWidth = useMemo(() => randomNumber(minWidth, maxWidth), [ + minWidth, + maxWidth, + ]); + return ; +} diff --git a/client/src/components/index.js b/client/src/components/index.js index 67b239915..3084f8c9b 100644 --- a/client/src/components/index.js +++ b/client/src/components/index.js @@ -44,7 +44,7 @@ import InputPrependText from './Forms/InputPrependText'; import PageFormBigNumber from './PageFormBigNumber'; import AccountsMultiSelect from './AccountsMultiSelect'; import CustomersMultiSelect from './CustomersMultiSelect'; - +import Skeleton from './Skeleton' import TableFastCell from './Datatable/TableFastCell'; @@ -97,6 +97,6 @@ export { AccountsMultiSelect, DataTableEditable, CustomersMultiSelect, - TableFastCell, + Skeleton, }; diff --git a/client/src/config/sidebarMenu.js b/client/src/config/sidebarMenu.js index d5dea66c3..4f4d90032 100644 --- a/client/src/config/sidebarMenu.js +++ b/client/src/config/sidebarMenu.js @@ -171,7 +171,8 @@ export default [ ], }, { - divider: true, + text: , + label: true, }, { text: , diff --git a/client/src/containers/Accounting/MakeJournalEntriesField.js b/client/src/containers/Accounting/MakeJournalEntriesField.js index 86f5e1c72..3286b422a 100644 --- a/client/src/containers/Accounting/MakeJournalEntriesField.js +++ b/client/src/containers/Accounting/MakeJournalEntriesField.js @@ -7,7 +7,6 @@ import { orderingLinesIndexes, repeatValue } from 'utils'; export default function MakeJournalEntriesField({ defaultRow, - linesNumber = 4, }) { return ( diff --git a/client/src/containers/Accounting/MakeJournalEntriesForm.js b/client/src/containers/Accounting/MakeJournalEntriesForm.js index 1cf3e2dcf..673105ef1 100644 --- a/client/src/containers/Accounting/MakeJournalEntriesForm.js +++ b/client/src/containers/Accounting/MakeJournalEntriesForm.js @@ -18,23 +18,20 @@ import MakeJournalEntriesField from './MakeJournalEntriesField'; import MakeJournalNumberWatcher from './MakeJournalNumberWatcher'; import MakeJournalFormFooter from './MakeJournalFormFooter'; -import withJournalsActions from 'containers/Accounting/withJournalsActions'; -import withManualJournalDetail from 'containers/Accounting/withManualJournalDetail'; -import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import withSettings from 'containers/Settings/withSettings'; import AppToaster from 'components/AppToaster'; -import Dragzone from 'components/Dragzone'; import withMediaActions from 'containers/Media/withMediaActions'; import { compose, repeatValue, orderingLinesIndexes, defaultToTransform, + transactionNumber, } from 'utils'; import { transformErrors } from './utils'; -import withManualJournalsActions from './withManualJournalsActions'; +import { useMakeJournalFormContext } from './MakeJournalProvider'; const defaultEntry = { index: 0, @@ -59,18 +56,6 @@ const defaultInitialValues = { * Journal entries form. */ function MakeJournalEntriesForm({ - // #withMedia - requestSubmitMedia, - requestDeleteMedia, - - // #withJournalsActions - requestMakeJournalEntries, - requestEditManualJournal, - setJournalNumberChanged, - - // #withManualJournals - journalNumberChanged, - // #withDashboard changePageTitle, changePageSubtitle, @@ -79,30 +64,33 @@ function MakeJournalEntriesForm({ journalNextNumber, journalNumberPrefix, baseCurrency, - // #ownProps - manualJournalId, - manualJournal, - onFormSubmit, - onCancelForm, }) { - const isNewMode = !manualJournalId; - const [submitPayload, setSubmitPayload] = useState({}); + const { + createJournalMutate, + editJournalMutate, + isNewMode, + manualJournal, + submitPayload, + } = useMakeJournalFormContext(); + const { formatMessage } = useIntl(); const history = useHistory(); - const journalNumber = isNewMode - ? `${journalNumberPrefix}-${journalNextNumber}` - : journalNextNumber; - + // New journal number. + const journalNumber = transactionNumber( + journalNumberPrefix, + journalNextNumber, + ); + // Changes the page title based on the form in new and edit mode. useEffect(() => { const transactionNumber = manualJournal ? manualJournal.journal_number : journalNumber; - if (manualJournal && manualJournal.id) { - changePageTitle(formatMessage({ id: 'edit_journal' })); - } else { + if (isNewMode) { changePageTitle(formatMessage({ id: 'new_journal' })); + } else { + changePageTitle(formatMessage({ id: 'edit_journal' })); } changePageSubtitle( defaultToTransform(transactionNumber, `No. ${transactionNumber}`, ''), @@ -113,6 +101,7 @@ function MakeJournalEntriesForm({ journalNumber, manualJournal, formatMessage, + isNewMode, ]); const initialValues = useMemo( @@ -131,7 +120,7 @@ function MakeJournalEntriesForm({ entries: orderingLinesIndexes(defaultInitialValues.entries), }), }), - [manualJournal, journalNumber], + [manualJournal, baseCurrency, journalNumber], ); // Handle journal number field change. @@ -144,6 +133,7 @@ function MakeJournalEntriesForm({ [changePageSubtitle], ); + // Handle the form submiting. const handleSubmit = (values, { setErrors, setSubmitting, resetForm }) => { setSubmitting(true); const entries = values.entries.filter( @@ -179,11 +169,13 @@ function MakeJournalEntriesForm({ } const form = { ...values, publish: submitPayload.publish, entries }; + // Handle the request error. const handleError = (error) => { transformErrors(error, { setErrors }); setSubmitting(false); }; + // Handle the request success. const handleSuccess = (errors) => { AppToaster.show({ message: formatMessage( @@ -196,7 +188,6 @@ function MakeJournalEntriesForm({ ), intent: Intent.SUCCESS, }); - setSubmitting(false); if (submitPayload.redirect) { @@ -208,25 +199,14 @@ function MakeJournalEntriesForm({ }; if (isNewMode) { - requestMakeJournalEntries(form).then(handleSuccess).catch(handleError); + createJournalMutate(form).then(handleSuccess).catch(handleError); } else { - requestEditManualJournal(manualJournal.id, form) + editJournalMutate(manualJournal.id, form) .then(handleSuccess) .catch(handleError); } }; - const handleCancelClick = useCallback(() => { - history.goBack(); - }, [history]); - - const handleSubmitClick = useCallback( - (event, payload) => { - setSubmitPayload({ ...payload }); - }, - [setSubmitPayload], - ); - return (
- {({ isSubmitting }) => ( -
- - - - - - - )} +
+ + + + + + - {/* */}
); } export default compose( - withJournalsActions, - withManualJournalDetail(), - withAccountsActions, withDashboardActions, withMediaActions, withSettings(({ manualJournalsSettings, organizationSettings }) => ({ @@ -280,5 +242,4 @@ export default compose( journalNumberPrefix: manualJournalsSettings?.numberPrefix, baseCurrency: organizationSettings?.baseCurrency, })), - withManualJournalsActions, )(MakeJournalEntriesForm); diff --git a/client/src/containers/Accounting/MakeJournalEntriesHeaderFields.js b/client/src/containers/Accounting/MakeJournalEntriesHeaderFields.js index ca2ae619b..3600deaa3 100644 --- a/client/src/containers/Accounting/MakeJournalEntriesHeaderFields.js +++ b/client/src/containers/Accounting/MakeJournalEntriesHeaderFields.js @@ -21,25 +21,24 @@ import { CurrencySelectList, } from 'components'; +import { useMakeJournalFormContext } from './MakeJournalProvider'; import withDialogActions from 'containers/Dialog/withDialogActions'; -import withCurrencies from 'containers/Currencies/withCurrencies'; import { compose, inputIntent, handleDateChange } from 'utils'; function MakeJournalEntriesHeader({ // #ownProps - manualJournal, onJournalNumberChanged, - // #withCurrencies - currenciesList, - // #withDialog openDialog, }) { - const handleJournalNumberChange = useCallback(() => { + const { currencies } = useMakeJournalFormContext(); + + // Handle journal number change. + const handleJournalNumberChange = () => { openDialog('journal-number-form', {}); - }, [openDialog]); + }; // Handle journal number field blur event. const handleJournalNumberChanged = (event) => { @@ -165,7 +164,7 @@ function MakeJournalEntriesHeader({ inline={true} > { form.setFieldValue('currency_code', currencyItem.currency_code); @@ -181,7 +180,4 @@ function MakeJournalEntriesHeader({ export default compose( withDialogActions, - withCurrencies(({ currenciesList }) => ({ - currenciesList, - })), )(MakeJournalEntriesHeader); diff --git a/client/src/containers/Accounting/MakeJournalEntriesPage.js b/client/src/containers/Accounting/MakeJournalEntriesPage.js index d129d3423..dfc405bf3 100644 --- a/client/src/containers/Accounting/MakeJournalEntriesPage.js +++ b/client/src/containers/Accounting/MakeJournalEntriesPage.js @@ -1,44 +1,26 @@ import React, { useCallback, useEffect } from 'react'; import { useParams, useHistory } from 'react-router-dom'; -import { useQuery } from 'react-query'; import MakeJournalEntriesForm from './MakeJournalEntriesForm'; -import DashboardInsider from 'components/Dashboard/DashboardInsider'; +import { MakeJournalProvider } from './MakeJournalProvider'; -import withCustomersActions from 'containers/Customers/withCustomersActions'; -import withAccountsActions from 'containers/Accounts/withAccountsActions'; -import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; -import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions'; -import withSettingsActions from 'containers/Settings/withSettingsActions'; import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import { compose } from 'utils'; -import 'style/pages/ManualJournal/MakeJournal.scss' +import 'style/pages/ManualJournal/MakeJournal.scss'; +/** + * Make journal entries page. + */ function MakeJournalEntriesPage({ - // #withCustomersActions - requestFetchCustomers, - - // #withAccountsActions - requestFetchAccounts, - - // #withManualJournalActions - requestFetchManualJournal, - - // #wihtCurrenciesActions - requestFetchCurrencies, - - // #withSettingsActions - requestFetchOptions, - // #withDashboardActions setSidebarShrink, resetSidebarPreviousExpand, - setDashboardBackLink + setDashboardBackLink, }) { const history = useHistory(); - const { id } = useParams(); + const { id: journalId } = useParams(); useEffect(() => { // Shrink the sidebar by foce. @@ -52,27 +34,7 @@ function MakeJournalEntriesPage({ // Hide the back link on dashboard topbar. setDashboardBackLink(false); }; - }, [resetSidebarPreviousExpand, setSidebarShrink]); - - const fetchAccounts = useQuery('accounts-list', (key) => - requestFetchAccounts(), - ); - - const fetchCustomers = useQuery('customers-list', (key) => - requestFetchCustomers(), - ); - - const fetchCurrencies = useQuery('currencies', () => - requestFetchCurrencies(), - ); - - const fetchSettings = useQuery(['settings'], () => requestFetchOptions({})); - - const fetchJournal = useQuery( - ['manual-journal', id], - (key, journalId) => requestFetchManualJournal(journalId), - { enabled: id && id }, - ); + }, [resetSidebarPreviousExpand, setDashboardBackLink, setSidebarShrink]); const handleFormSubmit = useCallback( (payload) => { @@ -86,29 +48,15 @@ function MakeJournalEntriesPage({ }, [history]); return ( - + - + ); } export default compose( - withAccountsActions, - withCustomersActions, - withManualJournalsActions, - withCurrenciesActions, - withSettingsActions, withDashboardActions, )(MakeJournalEntriesPage); diff --git a/client/src/containers/Accounting/MakeJournalEntriesTable.js b/client/src/containers/Accounting/MakeJournalEntriesTable.js index d9ecba07c..dbc089489 100644 --- a/client/src/containers/Accounting/MakeJournalEntriesTable.js +++ b/client/src/containers/Accounting/MakeJournalEntriesTable.js @@ -2,7 +2,7 @@ import React, { useState, useMemo, useEffect, useCallback } from 'react'; import { Button } from '@blueprintjs/core'; import { FormattedMessage as T, useIntl } from 'react-intl'; import { omit } from 'lodash'; -import { compose, saveInvoke } from 'utils'; +import { saveInvoke } from 'utils'; import { AccountsListFieldCell, MoneyFieldCell, @@ -18,21 +18,13 @@ import { } from './components'; import { DataTableEditable } from 'components'; -import withAccounts from 'containers/Accounts/withAccounts'; -import withCustomers from 'containers/Customers/withCustomers'; - import { updateDataReducer } from './utils'; +import { useMakeJournalFormContext } from './MakeJournalProvider'; /** * Make journal entries table component. */ -function MakeJournalEntriesTable({ - // #withCustomers - customers, - - // #withAccounts - accountsList, - +export default function MakeJournalEntriesTable({ // #ownPorps onClickRemoveRow, onClickAddNewRow, @@ -44,6 +36,8 @@ function MakeJournalEntriesTable({ const [rows, setRows] = useState([]); const { formatMessage } = useIntl(); + const { accounts, customers } = useMakeJournalFormContext(); + useEffect(() => { setRows([...entries.map((e) => ({ ...e, rowType: 'editor' }))]); }, [entries, setRows]); @@ -175,7 +169,7 @@ function MakeJournalEntriesTable({ sticky={true} totalRow={true} payload={{ - accounts: accountsList, + accounts, errors: error, updateData: handleUpdateData, removeRow: handleRemoveRow, @@ -209,12 +203,3 @@ function MakeJournalEntriesTable({ /> ); } - -export default compose( - withAccounts(({ accountsList }) => ({ - accountsList, - })), - withCustomers(({ customers }) => ({ - customers, - })), -)(MakeJournalEntriesTable); diff --git a/client/src/containers/Accounting/MakeJournalFormFloatingActions.js b/client/src/containers/Accounting/MakeJournalFormFloatingActions.js index 4df73ae9e..1d367b614 100644 --- a/client/src/containers/Accounting/MakeJournalFormFloatingActions.js +++ b/client/src/containers/Accounting/MakeJournalFormFloatingActions.js @@ -12,73 +12,64 @@ import { import { useFormikContext } from 'formik'; import classNames from 'classnames'; import { FormattedMessage as T } from 'react-intl'; -import { saveInvoke } from 'utils'; import { CLASSES } from 'common/classes'; import { Icon, If } from 'components'; +import { useHistory } from 'react-router-dom'; +import { useMakeJournalFormContext } from './MakeJournalProvider'; /** * Make Journal floating actions bar. */ -export default function MakeJournalFloatingAction({ - isSubmitting, - onSubmitClick, - onCancelClick, - manualJournal, -}) { - const { submitForm, resetForm } = useFormikContext(); +export default function MakeJournalFloatingAction() { + const history = useHistory(); + // Formik context. + const { submitForm, resetForm, isSubmitting } = useFormikContext(); + + // Make journal form context. + const { setSubmitPayload, manualJournal } = useMakeJournalFormContext(); + + // Handle submit & publish button click. const handleSubmitPublishBtnClick = (event) => { - saveInvoke(onSubmitClick, event, { - redirect: true, - publish: true, - }); + submitForm(); + setSubmitPayload({ redirect: true, publish: true }); }; + // Handle submit, publish & new button click. const handleSubmitPublishAndNewBtnClick = (event) => { submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: true, - resetForm: true, - }); + setSubmitPayload({ redirect: false, publish: true, resetForm: true }); }; + // Handle submit, publish & edit button click. const handleSubmitPublishContinueEditingBtnClick = (event) => { submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: true, - }); + setSubmitPayload({ redirect: false, publish: true }); }; + // Handle submit as draft button click. const handleSubmitDraftBtnClick = (event) => { - saveInvoke(onSubmitClick, event, { - redirect: true, - publish: false, - }); + setSubmitPayload({ redirect: true, publish: false }); }; + // Handle submit as draft & new button click. const handleSubmitDraftAndNewBtnClick = (event) => { submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: false, - resetForm: true, - }); + setSubmitPayload({ redirect: false, publish: false, resetForm: true }); }; + // Handle submit as draft & continue editing button click. const handleSubmitDraftContinueEditingBtnClick = (event) => { submitForm(); - saveInvoke(onSubmitClick, event, { - redirect: false, - publish: false, - }); + setSubmitPayload({ redirect: false, publish: false }); }; + // Handle cancel button click. const handleCancelBtnClick = (event) => { - saveInvoke(onCancelClick, event); + history.goBack(); }; + // Handle clear button click. const handleClearBtnClick = (event) => { resetForm(); }; @@ -90,6 +81,7 @@ export default function MakeJournalFloatingAction({ @@ -49,3 +65,7 @@ export default function InventoryAdjustmentFloatingActions({
); } + +export default compose( + withDialogActions +)(InventoryAdjustmentFloatingActions); \ No newline at end of file diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.js new file mode 100644 index 000000000..0b7ed4713 --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.js @@ -0,0 +1,90 @@ +import React from 'react'; +import moment from 'moment'; +import { Intent } from '@blueprintjs/core'; +import { Formik } from 'formik'; +import { omit, get } from 'lodash'; +import { useIntl } from 'react-intl'; + +import 'style/pages/Items/ItemAdjustmentDialog.scss'; + +import { AppToaster } from 'components'; +import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema'; + +import InventoryAdjustmentFormContent from './InventoryAdjustmentFormContent'; +import { useInventoryAdjContext } from './InventoryAdjustmentFormProvider'; + +import withDialogActions from 'containers/Dialog/withDialogActions'; +import { compose } from 'utils'; + +const defaultInitialValues = { + date: moment(new Date()).format('YYYY-MM-DD'), + type: 'decrement', + adjustment_account_id: '', + item_id: '', + reason: '', + cost: '', + quantity: '', + reference_no: '', + quantity_on_hand: '', + publish: '', +}; + +/** + * Inventory adjustment form. + */ +function InventoryAdjustmentForm({ + // #withDialogActions + closeDialog, +}) { + const { + dialogName, + item, + itemId, + submitPayload, + createInventoryAdjMutate, + } = useInventoryAdjContext(); + + const { formatMessage } = useIntl(); + + // Initial form values. + const initialValues = { + ...defaultInitialValues, + item_id: itemId, + quantity_on_hand: get(item, 'quantity_on_hand', 0), + }; + + // Handles the form submit. + const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + const form = { + ...omit(values, ['quantity_on_hand', 'new_quantity', 'action']), + publish: submitPayload.publish, + }; + setSubmitting(true); + createInventoryAdjMutate(form) + .then(() => { + closeDialog(dialogName); + + AppToaster.show({ + message: formatMessage({ + id: 'the_make_adjustment_has_been_created_successfully', + }), + intent: Intent.SUCCESS, + }); + }) + .finally(() => { + setSubmitting(true); + }); + }; + + return ( + + + + ); +} + +export default compose(withDialogActions)(InventoryAdjustmentForm); diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormContent.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormContent.js new file mode 100644 index 000000000..8d4e39c51 --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormContent.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Form } from 'formik'; +import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields'; +import InventoryAdjustmentFloatingActions from './InventoryAdjustmentFloatingActions'; + +/** + * Inventory adjustment form content. + */ +export default function InventoryAdjustmentFormContent() { + return ( +
+ + + + ); +} diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js index 65040ec5a..7ad032d07 100644 --- a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js @@ -1,142 +1,21 @@ -import React, { useState, useCallback } from 'react'; -import { Intent } from '@blueprintjs/core'; -import { Formik, Form } from 'formik'; -import { useIntl } from 'react-intl'; -import { useQuery, queryCache } from 'react-query'; -import moment from 'moment'; -import { omit, get } from 'lodash'; - +import React from 'react'; + import 'style/pages/Items/ItemAdjustmentDialog.scss'; - -import { AppToaster, DialogContent } from 'components'; - -import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema'; - -import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields'; -import InventoryAdjustmentFloatingActions from './InventoryAdjustmentFloatingActions'; - -import withDialogActions from 'containers/Dialog/withDialogActions'; -import withInventoryAdjustmentActions from 'containers/Items/withInventoryAdjustmentActions'; -import withAccountsActions from 'containers/Accounts/withAccountsActions'; -import withItem from 'containers/Items/withItem'; -import withItemsActions from 'containers/Items/withItemsActions'; - -import { compose } from 'utils'; - -const defaultInitialValues = { - date: moment(new Date()).format('YYYY-MM-DD'), - type: 'decrement', - adjustment_account_id: '', - item_id: '', - reason: '', - cost: '', - quantity: '', - reference_no: '', - quantity_on_hand: '', - publish: '', -}; + +import { InventoryAdjustmentFormProvider } from './InventoryAdjustmentFormProvider'; +import InventoryAdjustmentForm from './InventoryAdjustmentForm'; /** * Inventory adjustment form dialog content. */ -function InventoryAdjustmentFormDialogContent({ - // #withDialogActions - closeDialog, - - // #withAccountsActions - requestFetchAccounts, - - // #withInventoryAdjustmentActions - requestSubmitInventoryAdjustment, - - // #withItemsActions - requestFetchItem, - - // #withItem - item, - - // #ownProp - itemId, +export default function InventoryAdjustmentFormDialogContent({ + // #ownProps dialogName, + itemId }) { - const { formatMessage } = useIntl(); - const [submitPayload, setSubmitPayload] = useState({}); - - // Fetches accounts list. - const fetchAccount = useQuery('accounts-list', () => requestFetchAccounts()); - - // Fetches the item details. - const fetchItem = useQuery(['item', itemId], - (key, id) => requestFetchItem(id)); - - // Initial form values. - const initialValues = { - ...defaultInitialValues, - item_id: itemId, - quantity_on_hand: get(item, 'quantity_on_hand', 0), - }; - - // Handles the form submit. - const handleFormSubmit = (values, { setSubmitting, setErrors }) => { - const form = { - ...omit(values, ['quantity_on_hand', 'new_quantity', 'action']), - publish: submitPayload.publish, - }; - const onSuccess = ({ response }) => { - closeDialog(dialogName); - queryCache.invalidateQueries('accounts-list'); - queryCache.invalidateQueries('items-table'); - - AppToaster.show({ - message: formatMessage({ - id: 'the_make_adjustment_has_been_created_successfully', - }), - intent: Intent.SUCCESS, - }); - }; - const onError = (error) => { - setSubmitting(false); - }; - requestSubmitInventoryAdjustment({ form }).then(onSuccess).catch(onError); - }; - - // Handles dialog close. - const handleCloseClick = useCallback(() => { - closeDialog(dialogName); - }, [closeDialog, dialogName]); - - const handleSubmitClick = useCallback( - (event, payload) => { - setSubmitPayload({ ...payload }); - }, - [setSubmitPayload], - ); - return ( - - -
- - - -
-
+ + + ); } - -export default compose( - withInventoryAdjustmentActions, - withDialogActions, - withAccountsActions, - withItem(({ item }) => ({ - item: item - })), - withItemsActions, -)(InventoryAdjustmentFormDialogContent); diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js index 9623384bb..0505a901e 100644 --- a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js @@ -1,5 +1,5 @@ import React from 'react'; -import { FastField, ErrorMessage, Field, useFormikContext } from 'formik'; +import { FastField, ErrorMessage, Field } from 'formik'; import { Classes, FormGroup, @@ -10,7 +10,7 @@ import { import classNames from 'classnames'; import { FormattedMessage as T, useIntl } from 'react-intl'; import { DateInput } from '@blueprintjs/datetime'; -import { compose } from 'redux'; +import { useAutofocus } from 'hooks'; import { ListSelect, FieldRequiredHint, Col, Row } from 'components'; import { inputIntent, @@ -23,18 +23,20 @@ import { CLASSES } from 'common/classes'; import adjustmentType from 'common/adjustmentType'; import AccountsSuggestField from 'components/AccountsSuggestField'; -import withAccounts from 'containers/Accounts/withAccounts'; +import { useInventoryAdjContext } from './InventoryAdjustmentFormProvider' import { diffQuantity } from './utils'; import InventoryAdjustmentQuantityFields from './InventoryAdjustmentQuantityFields'; /** * Inventory adjustment form dialogs fields. */ -function InventoryAdjustmentFormDialogFields({ - //# withAccount - accountsList, -}) { - const { values } = useFormikContext(); +export default function InventoryAdjustmentFormDialogFields() { + const dateFieldRef = useAutofocus(); + + // Inventory adjustment dialog context. + const { accounts } = useInventoryAdjContext(); + + // Intl context. const { formatMessage } = useIntl(); return ( @@ -62,6 +64,7 @@ function InventoryAdjustmentFormDialogFields({ position: Position.BOTTOM, minimal: true, }} + inputRef={(ref) => (dateFieldRef.current = ref)} /> )} @@ -115,7 +118,7 @@ function InventoryAdjustmentFormDialogFields({ className={'form-group--adjustment-account'} > form.setFieldValue('adjustment_account_id', item.id) } @@ -159,9 +162,3 @@ function InventoryAdjustmentFormDialogFields({
); } - -export default compose( - withAccounts(({ accountsList }) => ({ - accountsList, - })), -)(InventoryAdjustmentFormDialogFields); diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormProvider.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormProvider.js new file mode 100644 index 000000000..5e8c1ab1f --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormProvider.js @@ -0,0 +1,51 @@ +import React, { useState, createContext } from 'react'; +import { DialogContent } from 'components'; +import { + useItem, + useAccounts, + useCreateInventoryAdjustment, +} from 'hooks/query'; + +const InventoryAdjustmentContext = createContext(); + +/** + * Inventory adjustment dialog provider. + */ +function InventoryAdjustmentFormProvider({ itemId, dialogName, ...props }) { + // Fetches accounts list. + const { isFetching: isAccountsLoading, data: accounts } = useAccounts(); + + // Fetches the item details. + const { isFetching: isItemLoading, data: item } = useItem(itemId); + + const { + mutateAsync: createInventoryAdjMutate, + } = useCreateInventoryAdjustment(); + + // Submit payload. + const [submitPayload, setSubmitPayload] = useState({}); + + // State provider. + const provider = { + itemId, + isAccountsLoading, + accounts, + isItemLoading, + item, + submitPayload, + dialogName, + + createInventoryAdjMutate, + setSubmitPayload, + }; + + return ( + + + + ); +} + +const useInventoryAdjContext = () => React.useContext(InventoryAdjustmentContext); + +export { InventoryAdjustmentFormProvider, useInventoryAdjContext }; diff --git a/client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryForm.js b/client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryForm.js index 774a27e30..bcb8981be 100644 --- a/client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryForm.js +++ b/client/src/containers/Dialogs/ItemCategoryDialog/ItemCategoryForm.js @@ -1,165 +1,111 @@ -import React, { useCallback } from 'react'; -import { - Button, - Classes, - FormGroup, - InputGroup, - Intent, - TextArea, - MenuItem, -} from '@blueprintjs/core'; -import { FormattedMessage as T } from 'react-intl'; -import classNames from 'classnames'; -import { ErrorMessage, Form, FastField } from 'formik'; -import { - ListSelect, - AccountsSelectList, - FieldRequiredHint, - Hint, -} from 'components'; -import { inputIntent } from 'utils'; +import React, { useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { Intent } from '@blueprintjs/core'; +import { Formik } from 'formik'; -import { useAutofocus } from 'hooks'; +import { AppToaster } from 'components'; +import { useItemCategoryContext } from './ItemCategoryProvider'; +import { transformToForm } from 'utils'; +import { + CreateItemCategoryFormSchema, + EditItemCategoryFormSchema, +} from './ItemCategoryForm.schema'; -export default function ItemCategoryForm({ - itemCategoryId, - accountsList, - categoriesList, - isSubmitting, - onClose, +import withDialogActions from 'containers/Dialog/withDialogActions'; +import ItemCategoryFormContent from './ItemCategoryFormContent' +import { compose } from 'utils'; + +const defaultInitialValues = { + name: '', + description: '', + cost_account_id: '', + sell_account_id: '', + inventory_account_id: '', +}; + +/** + * Item category form. + */ +function ItemCategoryForm({ + // #withDialogActions + closeDialog, }) { - const categoryNameFieldRef = useAutofocus(); + const { formatMessage } = useIntl(); + const { + isNewMode, + itemCategory, + itemCategoryId, + dialogName, + createItemCategoryMutate, + editItemCategoryMutate, + } = useItemCategoryContext(); + + // Initial values. + const initialValues = useMemo( + () => ({ + ...defaultInitialValues, + ...transformToForm(itemCategory, defaultInitialValues), + }), + [itemCategory], + ); + + // Transformes response errors. + const transformErrors = (errors, { setErrors }) => { + if (errors.find((error) => error.type === 'CATEGORY_NAME_EXISTS')) { + setErrors({ + name: formatMessage({ id: 'category_name_exists' }), + }); + } + }; + + // Handles the form submit. + const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + setSubmitting(true); + const form = { ...values }; + + // Handle close the dialog after success response. + const afterSubmit = () => { + closeDialog(dialogName); + }; + // Handle the response success/ + const onSuccess = ({ response }) => { + AppToaster.show({ + message: formatMessage({ + id: isNewMode + ? 'the_item_category_has_been_created_successfully' + : 'the_item_category_has_been_edited_successfully', + }), + intent: Intent.SUCCESS, + }); + afterSubmit(response); + }; + // Handle the response error. + const onError = (errors) => { + transformErrors(errors, { setErrors }); + setSubmitting(false); + }; + if (isNewMode) { + createItemCategoryMutate(form).then(onSuccess).catch(onError); + } else { + editItemCategoryMutate([itemCategoryId, form]) + .then(onSuccess) + .catch(onError); + } + }; return ( -
-
- {/* ----------- Category name ----------- */} - - {({ field, field: { value }, meta: { error, touched } }) => ( - } - labelInfo={} - className={'form-group--category-name'} - intent={inputIntent({ error, touched })} - helperText={} - inline={true} - > - (categoryNameFieldRef.current = ref)} - {...field} - /> - - )} - - - - {/* ----------- Description ----------- */} - - {({ field, field: { value }, meta: { error, touched } }) => ( - } - className={'form-group--description'} - intent={inputIntent({ error, touched })} - helperText={} - inline={true} - > -