@zeniai/client-epic-state 5.1.3-betaJK1 → 5.1.3-betaVR1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +0 -1
- package/lib/entity/task/taskPayload.d.ts +0 -1
- package/lib/entity/task/taskPayload.js +0 -1
- package/lib/entity/task/taskReducer.d.ts +1 -5
- package/lib/entity/task/taskReducer.js +2 -8
- package/lib/entity/task/taskState.d.ts +0 -1
- package/lib/epic.d.ts +1 -3
- package/lib/epic.js +1 -3
- package/lib/esm/entity/snackbar/snackbarTypes.js +0 -1
- package/lib/esm/entity/task/taskPayload.js +0 -1
- package/lib/esm/entity/task/taskReducer.js +1 -7
- package/lib/esm/epic.js +1 -3
- package/lib/esm/index.js +5 -4
- package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +200 -0
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +96 -2
- package/lib/esm/view/taskManager/taskDetailView/epics/fetchTaskDetailEpic.js +0 -13
- package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +2 -56
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +8 -19
- package/lib/index.d.ts +7 -6
- package/lib/index.js +41 -39
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +37 -2
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +205 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +28 -2
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +96 -2
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +39 -0
- package/lib/view/taskManager/taskDetailView/epics/fetchTaskDetailEpic.d.ts +1 -2
- package/lib/view/taskManager/taskDetailView/epics/fetchTaskDetailEpic.js +0 -13
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +0 -13
- package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +2 -14
- package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +3 -57
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +1 -2
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +6 -17
- package/package.json +2 -2
- package/lib/esm/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +0 -80
- package/lib/esm/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +0 -36
- package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.d.ts +0 -9
- package/lib/view/taskManager/taskDetailView/epics/createSubTaskEpic.js +0 -84
- package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.d.ts +0 -8
- package/lib/view/taskManager/taskDetailView/epics/fetchSubTasksEpic.js +0 -40
package/lib/esm/index.js
CHANGED
|
@@ -172,7 +172,7 @@ import { clearExpenseAutomationFluxAnalysisView, fetchFluxAnalysisView, reviewFl
|
|
|
172
172
|
import { clearJeScheduleLocalData as clearExpenseAutomationJEScheduleLocalData, clearExpenseAutomationJESchedulesView, fetchJeSchedulesPage as fetchExpenseAutomationJESchedulesPage, ignoreRecommendedJeSchedule as ignoreExpenseAutomationJESchedule, initializeAccountSettingsView as initializeJeAccountSettingsView, initializeJeScheduleLocalData, removeJeScheduleTransactionKey, retryJeSchedule as retryExpenseAutomationJESchedule, saveAccountSettings as saveJeAccountSettings, saveAccountSettingsLocalData as saveJeAccountSettingsLocalData, updateJESchedulesUIState as updateExpenseAutomationJESchedulesUIState, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, } from './view/expenseAutomationView/reducers/jeSchedulesViewReducer';
|
|
173
173
|
import { acknowledgeBulkUploadConfirmMatchComplete, bulkUploadAutomatchingTimedOut, bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, clearBulkUpload, clearBulkUploadBatchDetailsForScopeChange, clearManualSearchResults, clearMissingReceiptsTabNavigation, confirmBulkUploadMatch, confirmBulkUploadMatchFailure, confirmBulkUploadMatchSuccess, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsFailure, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, fetchCompletedTransactions, fetchCompletedTransactionsFailure, fetchCompletedTransactionsSuccess, fetchMissingReceipts as fetchExpenseAutomationMissingReceipts, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, markBatchDetailRefreshAttempted, markMissingReceiptAsDone as markExpenseAutomationMissingReceiptAsDone, pusherBatchStatusUpdate, refreshBatchDetailsForBatchId, requestMissingReceiptsTabNavigation, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, searchTransactionsForManualMatch, searchTransactionsForManualMatchFailure, searchTransactionsForManualMatchSuccess, setBulkUploadCompletedSubTab, setBulkUploadResultsTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, storeBatchDetails, updateBulkUploadProgress, updateMissingReceiptUploadState as updateExpenseAutomationMissingReceiptUploadState, updateMissingReceiptsUIState as updateExpenseAutomationMissingReceiptsUIState, uploadMissingReceiptSuccess as uploadExpenseAutomationMissingReceiptSuccess, } from './view/expenseAutomationView/reducers/missingReceiptsViewReducer';
|
|
174
174
|
import { deleteAccountStatement, excludeAccountFromReconciliation, fetchReconciliation as fetchReconciliationView, includeAccountInReconciliation, saveReconciliationDetail as saveExpenseAutomationReconciliationDetail, saveReconciliationReview as saveExpenseAutomationReconciliationReview, setConnectionInProgressForAccount as setConnectionInProgressForAccountReconciliation, setStatementParseInProgress, updateAccountReconciliationLocalData as updateExpenseAutomationAccountReconciliationLocalData, updateSelectedAccountId as updateExpenseAutomationAccountReconciliationSelectedAccountId, updateSelectedTab as updateExpenseAutomationAccountReconciliationSelectedTab, updateReconListScrollPosition as updateExpenseAutomationReconListScrollPosition, updateReviewTabSortState as updateExpenseAutomationReconReviewTabListSortState, updateReviewTabLocalData as updateExpenseAutomationReconReviewTabLocalData, updateReconcileTabListScrollState as updateExpenseAutomationReconcileTabListScrollState, updateReconcileTabListSortState as updateExpenseAutomationReconcileTabListSortState, updateReconcileTabLocalData as updateExpenseAutomationReconcileTabLocalData, updateSelectedDrawerAccountId as updateExpenseAutomationSelectedDrawerAccountId, updateNodeCollapseState, updateStatementUploadChosen, uploadAccountStatement, } from './view/expenseAutomationView/reducers/reconciliationViewReducer';
|
|
175
|
-
import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fetchTransactionCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationView, initializeTransactionCategorizationViewLocalData, markCategoryClassRecommendationsFailureForCategorization, markTransactionAsNotMiscategorized, removeTransactionFromAllTabs, saveTransactionCategorization, saveTransactionCategorizationLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, setEntityRecommendationForLineIdsForCategorization, syncTransactionCategorizationFromDetailSave, updateCurrentSelectedTransactionCategorizationTab, updateSelectedCheckboxTransactionIds, updateSelectedCustomerForTransaction, updateSelectedTransactionId, updateSelectedVendorForTransaction, updateTransactionCategorization, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, updateTransactionCategorizationUIState, updateTransactionCategorizationUploadReceiptState, updateTransactionFilters, uploadTransactionCategorizationReceiptSuccess, } from './view/expenseAutomationView/reducers/transactionsViewReducer';
|
|
175
|
+
import { backgroundRefetchReviewTab, clearExpenseAutomationTransactionsView, fetchTransactionCategorization, applyFieldToEmptyLinesForCategorization, clearLastEditedFieldForApplyToEmptyForCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationView, initializeTransactionCategorizationViewLocalData, markCategoryClassRecommendationsFailureForCategorization, markTransactionAsNotMiscategorized, removeTransactionFromAllTabs, saveTransactionCategorization, saveTransactionCategorizationLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, setEntityRecommendationForLineIdsForCategorization, setLastEditedFieldForApplyToEmptyForCategorization, syncTransactionCategorizationFromDetailSave, updateCurrentSelectedTransactionCategorizationTab, updateSelectedCheckboxTransactionIds, updateSelectedCustomerForTransaction, updateSelectedTransactionId, updateSelectedVendorForTransaction, updateTransactionCategorization, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, updateTransactionCategorizationUIState, updateTransactionCategorizationUploadReceiptState, updateTransactionFilters, uploadTransactionCategorizationReceiptSuccess, } from './view/expenseAutomationView/reducers/transactionsViewReducer';
|
|
176
176
|
import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
|
|
177
177
|
import { getExpenseAutomationReconciliationView, isAccountReconReport, } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
|
|
178
178
|
import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
|
|
@@ -183,6 +183,7 @@ import { BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBat
|
|
|
183
183
|
import { toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey, } from './view/expenseAutomationView/types/missingReceiptsViewState';
|
|
184
184
|
import { toReconciliationTabsType, } from './view/expenseAutomationView/types/reconciliationViewState';
|
|
185
185
|
import { toTransactionsTabKey as toExpenseAutomationTransactionsTabKey, toTransactionsSortKey, } from './view/expenseAutomationView/types/transactionsViewState';
|
|
186
|
+
import { isLineFieldEmpty } from './view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper';
|
|
186
187
|
import { clearFeatureNotificationView, fetchRegisteredInterests, notifyMeForFeature, } from './view/featureNotificationView/featureNotificationViewReducer';
|
|
187
188
|
import { getFeatureNotificationView, getRegisteredInterests, getRegisteredInterestsByFeature, isFeatureInterestRegistered, } from './view/featureNotificationView/featureNotificationViewSelector';
|
|
188
189
|
import downloadFile from './view/fileView/fileDownloadHelpers';
|
|
@@ -374,7 +375,7 @@ import { getAllTags } from './view/tagView/tagViewSelector';
|
|
|
374
375
|
import { deleteCannedResponse, fetchCannedResponses, saveCannedResponse, } from './view/taskManager/cannedResponsesView/cannedResponsesReducer';
|
|
375
376
|
import { getCannedResponsesView } from './view/taskManager/cannedResponsesView/cannedResponsesSelector';
|
|
376
377
|
import { initialTaskDetail, initialTaskDetailLocalData, } from './view/taskManager/taskDetailView/taskDetail';
|
|
377
|
-
import { archiveTask,
|
|
378
|
+
import { archiveTask, deleteTask, discardTaskUpdatesInLocalStore, fetchTaskDetailPage, saveTaskDetail, saveTaskUpdatesToLocalStore, snoozeTask, unsnoozeTask, } from './view/taskManager/taskDetailView/taskDetailReducer';
|
|
378
379
|
import { allTaskPriority, allTaskStatus, getTaskDetail, } from './view/taskManager/taskDetailView/taskDetailSelector';
|
|
379
380
|
import { createTaskFromTaskGroupTemplate } from './view/taskManager/taskGroupTemplateView/taskGroupTemplateViewReducer';
|
|
380
381
|
import { createNewTaskGroup, deleteTaskGroup, fetchAllTaskGroups, updateTaskGroupName, } from './view/taskManager/taskGroupView/taskGroupViewReducer';
|
|
@@ -458,7 +459,7 @@ export {
|
|
|
458
459
|
BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, toExpenseAutomationJEScheduleMainTab, toExpenseAutomationJEScheduleSortKey, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, fetchExpenseAutomationMissingReceipts,
|
|
459
460
|
// Bulk Upload Actions
|
|
460
461
|
bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, getExpenseAutomationFluxAnalysisView, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, updateFluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, getExpenseAutomationReconciliationView, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, uploadAccountStatement, updateNodeCollapseState, updateStatementUploadChosen, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, };
|
|
461
|
-
export { fetchTransactionCategorization, fetchTransactionCategorizationView, updateTransactionCategorizationUIState, updateTransactionFilters, updateSelectedCheckboxTransactionIds, markCategoryClassRecommendationsFailureForCategorization, setEntityRecommendationForLineIdsForCategorization, initializeTransactionCategorizationViewLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, createTransferEntry, createTransferEntryFailure, createTransferEntryReplacedTransaction, createTransferEntrySuccess, resetCreateTransferEntryStatus, clearTransferEntryRouteReplacement, fetchAccountsForTransferFlow, removeTransactionFromAllTabs, clearExpenseAutomationTransactionsView, toTransactionsSortKey, };
|
|
462
|
+
export { fetchTransactionCategorization, fetchTransactionCategorizationView, updateTransactionCategorizationUIState, updateTransactionFilters, updateSelectedCheckboxTransactionIds, markCategoryClassRecommendationsFailureForCategorization, setEntityRecommendationForLineIdsForCategorization, setLastEditedFieldForApplyToEmptyForCategorization, applyFieldToEmptyLinesForCategorization, clearLastEditedFieldForApplyToEmptyForCategorization, initializeTransactionCategorizationViewLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, createTransferEntry, createTransferEntryFailure, createTransferEntryReplacedTransaction, createTransferEntrySuccess, resetCreateTransferEntryStatus, clearTransferEntryRouteReplacement, fetchAccountsForTransferFlow, removeTransactionFromAllTabs, clearExpenseAutomationTransactionsView, toTransactionsSortKey, isLineFieldEmpty, };
|
|
462
463
|
export { TOP_EX_TIME_PERIODS };
|
|
463
464
|
export { toTimeframeTick, mapTimePeriodtoTimeframeTick, toTimePeriod, toAbsoluteDay, toMonthYearPeriodId, convertToPeriod, };
|
|
464
465
|
export { toVendorSpendTrendFilterTabsTypeStrict, } from './entity/vendorExpense/vendorExpenseSelector';
|
|
@@ -627,7 +628,7 @@ export { fetchGlobalMerchantRecommendation, createGlobalMerchant, updateCreateGl
|
|
|
627
628
|
export { approveVendorGlobalReview, rejectVendorGlobalReview, fetchVendorGlobalReviewView, updateSelectedGlobalMerchant, updateVendorGlobalReviewViewUIState, getVendorGlobalReviewView, getTenantMerchantByMerchantId, toVendorGlobalReviewColumnSortKeyType, updateVendorGlobalReviewViewLocalData, };
|
|
628
629
|
export { fetchArAging, updateArAgingUIState, fetchArAgingDetail, updateArAgingDetailUIState, getArAgingReport, getArAgingDetailForCustomer, updateArAgingNodeCollapseState, };
|
|
629
630
|
export { toRecurringBillFrequency, toRecurringBillFrequencyStrict, };
|
|
630
|
-
export { getTaskGroupById, getAllTasks, fetchTaskListPage, getTaskDetail, fetchTaskDetailPage, saveTaskUpdatesToLocalStore, saveTaskDetail,
|
|
631
|
+
export { getTaskGroupById, getAllTasks, fetchTaskListPage, getTaskDetail, fetchTaskDetailPage, saveTaskUpdatesToLocalStore, saveTaskDetail, archiveTask, fetchCannedResponses, saveCannedResponse, deleteCannedResponse, getCannedResponsesView, updateTaskListSearchText, updateTaskListUIState, allTaskStatus, allTaskPriority, updateTaskFilters, TASK_LIST_FILTER_CATEGORIES, TASK_LIST_GROUP_BY_CATEGORIES, deleteTask, discardTaskUpdatesInLocalStore, bulkUpdateTaskList, createNewTaskGroup, initiateTaskListLocalData, deleteTaskGroup, updateTaskListLocalData, dragNDropTasks, updateTaskGroupName, toTaskListGroupByKeyType, toTaskListGroupByKeyTypeStrict, getTaskUpdates, fetchAllTaskGroups, initialTaskDetail, getDueDateValueFromDueDateGroupId, toPriorityCodeType, toTaskStatusCodeType, toDueDateGroupKeyType, updateTaskFromListView, updateTaskListTab, removeTaskFromList, snoozeTask, unsnoozeTask, convertHHMMStrToMinutes, initialTaskDetailLocalData, ALL_TASK_LIST_TABS, };
|
|
631
632
|
export { getAllTags, fetchTagList, createTag, deleteTag, };
|
|
632
633
|
export { getAllCardsAndBankPaymentMethods, createCardSetupIntent, confirmCardSetupIntent, addCardPaymentSource, fetchPaymentSources, resetCardPaymentErrorStatuses, clearCardPaymentView, };
|
|
633
634
|
export { getAuditReportGroupViewSelectorView, getAuditRuleGroupViewSelectorView, getUserFromAllUsers, fetchAuditRuleGroupView, fetchAuditReportGroupView, saveReasonForAuditRule, clearAuditReportGroupViewByCompanyId, };
|
package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js
CHANGED
|
@@ -764,3 +764,203 @@ export const hasTransactionLocalDataChanges = (transaction, transactionReviewLoc
|
|
|
764
764
|
}
|
|
765
765
|
return false;
|
|
766
766
|
};
|
|
767
|
+
// =========================================================================
|
|
768
|
+
// Apply-to-Empty-Lines helpers
|
|
769
|
+
//
|
|
770
|
+
// Drives the contextual "Apply <value> to <count> empty <field>" banner on
|
|
771
|
+
// the Transaction Categorization List page (Pending Review tab). The banner
|
|
772
|
+
// triggers when the user fills in Category / Class / per-line Vendor on one
|
|
773
|
+
// line of a multi-line transaction; the helpers below compute which sibling
|
|
774
|
+
// lines are eligible (per-field, INDEPENDENT) and mutate only that field
|
|
775
|
+
// when the user clicks Apply.
|
|
776
|
+
//
|
|
777
|
+
// Empty-field detection mirrors the existing categorization auto-fill rules:
|
|
778
|
+
// - Category empty when `account.qboId == null` OR the account is one of
|
|
779
|
+
// the company's uncategorized accounts.
|
|
780
|
+
// - Class empty when `class.qboId == null` AND `class.classId == null`.
|
|
781
|
+
// - Vendor empty when the line carries no `lineEntity` / `vendor` /
|
|
782
|
+
// `customer`. Only `journal_entry` / `deposit` transactions surface
|
|
783
|
+
// a per-line vendor — for other transaction types vendor is
|
|
784
|
+
// transaction-level and the banner is not offered.
|
|
785
|
+
// =========================================================================
|
|
786
|
+
const PER_LINE_VENDOR_TRANSACTION_TYPES = [
|
|
787
|
+
'journal_entry',
|
|
788
|
+
'deposit',
|
|
789
|
+
];
|
|
790
|
+
/**
|
|
791
|
+
* Returns true iff the *specific field* is empty on this line. The three
|
|
792
|
+
* fields are evaluated INDEPENDENTLY — eligibility for a Category Apply
|
|
793
|
+
* depends solely on the line's category emptiness, irrespective of class
|
|
794
|
+
* / vendor on the same line.
|
|
795
|
+
*/
|
|
796
|
+
export const isLineFieldEmpty = (line, field, transactionType, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled = false) => {
|
|
797
|
+
switch (field) {
|
|
798
|
+
case 'category': {
|
|
799
|
+
const categoryId = line.account?.qboId ?? line.account?.accountId;
|
|
800
|
+
if (categoryId == null) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
803
|
+
if (uncategorizedAccounts == null) {
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
return isAccountUncategorized(uncategorizedAccounts, categoryId, isUncategorizedExpenseCategoryEnabled === true ? ['income'] : undefined);
|
|
807
|
+
}
|
|
808
|
+
case 'class': {
|
|
809
|
+
// Class has no separate "uncategorized" concept — empty iff both
|
|
810
|
+
// candidate ids are missing. Mirrors the existing auto-fill check
|
|
811
|
+
// at L564 above (`record.class?.qboId == null`) plus the legacy
|
|
812
|
+
// detail-page emptiness convention (qboId OR classId).
|
|
813
|
+
return line.class?.qboId == null && line.class?.classId == null;
|
|
814
|
+
}
|
|
815
|
+
case 'vendor': {
|
|
816
|
+
if (transactionType == null ||
|
|
817
|
+
PER_LINE_VENDOR_TRANSACTION_TYPES.includes(transactionType) === false) {
|
|
818
|
+
// Vendor is transaction-scoped (header) for non-JE / non-deposit
|
|
819
|
+
// transactions, so per-line vendor emptiness is meaningless and
|
|
820
|
+
// we never offer the Apply banner there.
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
return (line.lineEntity == null && line.vendor == null && line.customer == null);
|
|
824
|
+
}
|
|
825
|
+
default:
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
/**
|
|
830
|
+
* Computes the eligible empty-line ids for a given field+transaction.
|
|
831
|
+
* Excludes the source line (the one the user edited) since the user
|
|
832
|
+
* already filled THAT line — the banner is about propagating to siblings.
|
|
833
|
+
*/
|
|
834
|
+
const computeEligibleEmptyLineIds = (localData, field, sourceLineId, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled = false) => {
|
|
835
|
+
const eligibleIds = [];
|
|
836
|
+
for (const lineId of localData.sortedLineItems) {
|
|
837
|
+
if (lineId === sourceLineId) {
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const line = localData.lineItemById[lineId];
|
|
841
|
+
if (line == null) {
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
if (isLineFieldEmpty(line, field, localData.transactionType, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled)) {
|
|
845
|
+
eligibleIds.push(lineId);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
return eligibleIds;
|
|
849
|
+
};
|
|
850
|
+
/**
|
|
851
|
+
* Replaces (not merges) the apply-to-empty banner state on the local
|
|
852
|
+
* data. Called by the categorization watch handler whenever the user
|
|
853
|
+
* changes Category / Class / per-line Vendor on a line. Returns a fresh
|
|
854
|
+
* copy of the local data; if no sibling lines have the corresponding
|
|
855
|
+
* field empty, the banner is hidden by leaving `applyToEmptyState` null.
|
|
856
|
+
*/
|
|
857
|
+
export const toSetLastEditedFieldForApplyToEmpty = (transactionLocalData, field, sourceLineId, value, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled = false) => {
|
|
858
|
+
const eligibleEmptyLineIds = computeEligibleEmptyLineIds(transactionLocalData, field, sourceLineId, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled);
|
|
859
|
+
if (eligibleEmptyLineIds.length === 0) {
|
|
860
|
+
// No siblings to fill — drop any prior banner so we don't leave a
|
|
861
|
+
// stale proposal up.
|
|
862
|
+
return {
|
|
863
|
+
...transactionLocalData,
|
|
864
|
+
applyToEmptyState: null,
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
const next = {
|
|
868
|
+
field,
|
|
869
|
+
sourceLineId,
|
|
870
|
+
valueLabel: value.valueLabel,
|
|
871
|
+
eligibleEmptyLineIds,
|
|
872
|
+
account: value.account,
|
|
873
|
+
classBase: value.classBase,
|
|
874
|
+
entity: value.entity,
|
|
875
|
+
};
|
|
876
|
+
return {
|
|
877
|
+
...transactionLocalData,
|
|
878
|
+
applyToEmptyState: next,
|
|
879
|
+
};
|
|
880
|
+
};
|
|
881
|
+
/**
|
|
882
|
+
* Mutates ONLY the banner's field on each line whose field is currently
|
|
883
|
+
* empty (re-checked against live state). Other lines and other fields are
|
|
884
|
+
* untouched. Mirrors the per-field, INDEPENDENT rule from the PRD.
|
|
885
|
+
*
|
|
886
|
+
* After applying, the banner state is cleared. Returns a fresh copy of
|
|
887
|
+
* the local data.
|
|
888
|
+
*/
|
|
889
|
+
export const toApplyFieldToEmptyLines = (transactionLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled = false) => {
|
|
890
|
+
const state = transactionLocalData.applyToEmptyState;
|
|
891
|
+
if (state == null) {
|
|
892
|
+
return transactionLocalData;
|
|
893
|
+
}
|
|
894
|
+
const newLineItems = {};
|
|
895
|
+
for (const lineId of transactionLocalData.sortedLineItems) {
|
|
896
|
+
const line = transactionLocalData.lineItemById[lineId];
|
|
897
|
+
if (line == null) {
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
// Re-check emptiness against the current line state — the user could
|
|
901
|
+
// have manually filled some of these in between the set and apply.
|
|
902
|
+
if (lineId !== state.sourceLineId &&
|
|
903
|
+
state.eligibleEmptyLineIds.includes(lineId) &&
|
|
904
|
+
isLineFieldEmpty(line, state.field, transactionLocalData.transactionType, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled)) {
|
|
905
|
+
const updated = { ...line };
|
|
906
|
+
switch (state.field) {
|
|
907
|
+
case 'category':
|
|
908
|
+
if (state.account != null) {
|
|
909
|
+
updated.account = state.account;
|
|
910
|
+
}
|
|
911
|
+
break;
|
|
912
|
+
case 'class':
|
|
913
|
+
if (state.classBase != null) {
|
|
914
|
+
updated.class = state.classBase;
|
|
915
|
+
}
|
|
916
|
+
break;
|
|
917
|
+
case 'vendor':
|
|
918
|
+
if (state.entity != null) {
|
|
919
|
+
updated.lineEntity = state.entity;
|
|
920
|
+
// Mirror the legacy split-by-type behavior (see
|
|
921
|
+
// `setEntityRecommendationForLineIdInLocalData` -> entity
|
|
922
|
+
// shape). Keep `vendor` / `customer` legs in sync so
|
|
923
|
+
// downstream save flows that read either side stay correct.
|
|
924
|
+
if (state.entity.type === 'vendor') {
|
|
925
|
+
// VendorBase has {id, name, logo?} — no qboId field.
|
|
926
|
+
updated.vendor = {
|
|
927
|
+
id: state.entity.id,
|
|
928
|
+
name: state.entity.name,
|
|
929
|
+
logo: state.entity.logo,
|
|
930
|
+
};
|
|
931
|
+
updated.customer = undefined;
|
|
932
|
+
}
|
|
933
|
+
else if (state.entity.type === 'customer') {
|
|
934
|
+
updated.customer = {
|
|
935
|
+
id: state.entity.id,
|
|
936
|
+
name: state.entity.name,
|
|
937
|
+
logo: state.entity.logo,
|
|
938
|
+
qboId: state.entity.qboId,
|
|
939
|
+
};
|
|
940
|
+
updated.vendor = undefined;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
break;
|
|
944
|
+
default:
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
newLineItems[lineId] = updated;
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
newLineItems[lineId] = line;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
...transactionLocalData,
|
|
955
|
+
lineItemById: newLineItems,
|
|
956
|
+
applyToEmptyState: null,
|
|
957
|
+
};
|
|
958
|
+
};
|
|
959
|
+
/**
|
|
960
|
+
* Clears the apply-to-empty banner state. Used by Dismiss as well as on
|
|
961
|
+
* save / discard / transaction-context-change.
|
|
962
|
+
*/
|
|
963
|
+
export const toClearApplyToEmpty = (transactionLocalData) => ({
|
|
964
|
+
...transactionLocalData,
|
|
965
|
+
applyToEmptyState: null,
|
|
966
|
+
});
|
|
@@ -3,7 +3,7 @@ import recordGet from 'lodash/get';
|
|
|
3
3
|
import uniq from 'lodash/uniq';
|
|
4
4
|
import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
|
|
5
5
|
import { isVendorTransaction } from '../../../entity/transaction/stateTypes/vendorTransaction';
|
|
6
|
-
import { filterAutoTabLineItems, mergeTabSpecificLineItems, removeTransactionFromTabView, setEntityRecommendationForLineIdInLocalData, shouldAutoSelectAndAdd, toSetAllLineItemsToCategoryClass, toTransactionDetailLocalData, } from '../helpers/transactionCategorizationLocalDataHelper';
|
|
6
|
+
import { filterAutoTabLineItems, mergeTabSpecificLineItems, removeTransactionFromTabView, setEntityRecommendationForLineIdInLocalData, shouldAutoSelectAndAdd, toApplyFieldToEmptyLines, toClearApplyToEmpty, toSetAllLineItemsToCategoryClass, toSetLastEditedFieldForApplyToEmpty, toTransactionDetailLocalData, } from '../helpers/transactionCategorizationLocalDataHelper';
|
|
7
7
|
import { DEFAULT_COMPLETED_SUB_TAB, } from '../types/completedSubTab';
|
|
8
8
|
import { TRANSACTIONS_TABS, } from '../types/transactionsViewState';
|
|
9
9
|
export const initialTransactionTabViewState = {
|
|
@@ -1052,7 +1052,101 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
1052
1052
|
}
|
|
1053
1053
|
},
|
|
1054
1054
|
},
|
|
1055
|
+
/**
|
|
1056
|
+
* Records the user's most-recent Category / Class / per-line Vendor
|
|
1057
|
+
* edit on a multi-line transaction, computes the sibling lines whose
|
|
1058
|
+
* SAME field is currently empty, and stores the result on
|
|
1059
|
+
* `applyToEmptyState`. The categorization list row reads that state
|
|
1060
|
+
* to render the "Apply <value> to <count> empty <field>" banner.
|
|
1061
|
+
*/
|
|
1062
|
+
setLastEditedFieldForApplyToEmptyForCategorization: {
|
|
1063
|
+
prepare(selectedTab, transactionId, field, sourceLineId, value, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled) {
|
|
1064
|
+
return {
|
|
1065
|
+
payload: {
|
|
1066
|
+
selectedTab,
|
|
1067
|
+
transactionId,
|
|
1068
|
+
field,
|
|
1069
|
+
sourceLineId,
|
|
1070
|
+
value,
|
|
1071
|
+
uncategorizedAccounts,
|
|
1072
|
+
isUncategorizedExpenseCategoryEnabled,
|
|
1073
|
+
},
|
|
1074
|
+
};
|
|
1075
|
+
},
|
|
1076
|
+
reducer(draft, action) {
|
|
1077
|
+
const { selectedTab, transactionId, field, sourceLineId, value, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
1078
|
+
const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
|
|
1079
|
+
.transactionReviewLocalDataById, transactionId, undefined);
|
|
1080
|
+
if (transactionLocalData == null) {
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
const next = toSetLastEditedFieldForApplyToEmpty(transactionLocalData.transactionReviewLocalData, field, sourceLineId, value, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled);
|
|
1084
|
+
draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transactionId] = {
|
|
1085
|
+
transactionId,
|
|
1086
|
+
transactionReviewLocalData: next,
|
|
1087
|
+
};
|
|
1088
|
+
},
|
|
1089
|
+
},
|
|
1090
|
+
/**
|
|
1091
|
+
* Applies the value tracked in `applyToEmptyState` to the eligible
|
|
1092
|
+
* empty lines (re-checked at apply time) and clears the banner. Only
|
|
1093
|
+
* the banner's field is mutated — every other field on those lines
|
|
1094
|
+
* is preserved.
|
|
1095
|
+
*/
|
|
1096
|
+
applyFieldToEmptyLinesForCategorization: {
|
|
1097
|
+
prepare(selectedTab, transactionId, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled) {
|
|
1098
|
+
return {
|
|
1099
|
+
payload: {
|
|
1100
|
+
selectedTab,
|
|
1101
|
+
transactionId,
|
|
1102
|
+
uncategorizedAccounts,
|
|
1103
|
+
isUncategorizedExpenseCategoryEnabled,
|
|
1104
|
+
},
|
|
1105
|
+
};
|
|
1106
|
+
},
|
|
1107
|
+
reducer(draft, action) {
|
|
1108
|
+
const { selectedTab, transactionId, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
1109
|
+
const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
|
|
1110
|
+
.transactionReviewLocalDataById, transactionId, undefined);
|
|
1111
|
+
if (transactionLocalData == null) {
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
const next = toApplyFieldToEmptyLines(transactionLocalData.transactionReviewLocalData, uncategorizedAccounts, isUncategorizedExpenseCategoryEnabled);
|
|
1115
|
+
draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transactionId] = {
|
|
1116
|
+
transactionId,
|
|
1117
|
+
transactionReviewLocalData: next,
|
|
1118
|
+
};
|
|
1119
|
+
// Mark the transaction dirty so the existing Save flow picks up
|
|
1120
|
+
// the propagated edits.
|
|
1121
|
+
const dirtyIds = draft.transactionCategorizationView[selectedTab]
|
|
1122
|
+
.transactionIdsWithUnsavedData;
|
|
1123
|
+
if (dirtyIds.includes(transactionId) === false) {
|
|
1124
|
+
dirtyIds.push(transactionId);
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
},
|
|
1128
|
+
/**
|
|
1129
|
+
* Clears the apply-to-empty banner state. Used by Dismiss and any
|
|
1130
|
+
* transaction-context change (save / discard / unmount).
|
|
1131
|
+
*/
|
|
1132
|
+
clearLastEditedFieldForApplyToEmptyForCategorization: {
|
|
1133
|
+
prepare(selectedTab, transactionId) {
|
|
1134
|
+
return { payload: { selectedTab, transactionId } };
|
|
1135
|
+
},
|
|
1136
|
+
reducer(draft, action) {
|
|
1137
|
+
const { selectedTab, transactionId } = action.payload;
|
|
1138
|
+
const transactionLocalData = recordGet(draft.transactionCategorizationView[selectedTab]
|
|
1139
|
+
.transactionReviewLocalDataById, transactionId, undefined);
|
|
1140
|
+
if (transactionLocalData == null) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
draft.transactionCategorizationView[selectedTab].transactionReviewLocalDataById[transactionId] = {
|
|
1144
|
+
transactionId,
|
|
1145
|
+
transactionReviewLocalData: toClearApplyToEmpty(transactionLocalData.transactionReviewLocalData),
|
|
1146
|
+
};
|
|
1147
|
+
},
|
|
1148
|
+
},
|
|
1055
1149
|
},
|
|
1056
1150
|
});
|
|
1057
|
-
export const { fetchTransactionCategorization, updateTransactionCategorizationUIState, updateTransactionFilters, initializeTransactionCategorizationViewLocalData, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, setAllItemsToCategoryClassInLocalDataForCategorization, updateTotalCountForTransactionCategorization, updateParentTotalCountForTab, fetchTransactionCategorizationSuccess, resetOtherTabsFetchState, fetchTransactionCategorizationView, updateSelectedCheckboxTransactionIds, clearExpenseAutomationTransactionsViewPerTabView, clearExpenseAutomationTransactionsView, setEntityRecommendationForLineIdsForCategorization, markCategoryClassRecommendationsInProgressForCategorization, markCategoryClassRecommendationsCompletedForCategorization, markCategoryClassRecommendationsFailureForCategorization, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, removeTransactionFromAllTabs, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, } = expenseAutomationTransactionsView.actions;
|
|
1151
|
+
export const { fetchTransactionCategorization, updateTransactionCategorizationUIState, updateTransactionFilters, initializeTransactionCategorizationViewLocalData, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, setAllItemsToCategoryClassInLocalDataForCategorization, updateTotalCountForTransactionCategorization, updateParentTotalCountForTab, fetchTransactionCategorizationSuccess, resetOtherTabsFetchState, fetchTransactionCategorizationView, updateSelectedCheckboxTransactionIds, clearExpenseAutomationTransactionsViewPerTabView, clearExpenseAutomationTransactionsView, setEntityRecommendationForLineIdsForCategorization, markCategoryClassRecommendationsInProgressForCategorization, markCategoryClassRecommendationsCompletedForCategorization, markCategoryClassRecommendationsFailureForCategorization, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, removeTransactionFromAllTabs, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, setLastEditedFieldForApplyToEmptyForCategorization, applyFieldToEmptyLinesForCategorization, clearLastEditedFieldForApplyToEmptyForCategorization, } = expenseAutomationTransactionsView.actions;
|
|
1058
1152
|
export default expenseAutomationTransactionsView.reducer;
|
|
@@ -4,16 +4,13 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
|
4
4
|
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
5
5
|
import { updateTags } from '../../../../entity/tag/tagReducer';
|
|
6
6
|
import { updateTasks } from '../../../../entity/task/taskReducer';
|
|
7
|
-
import { getTaskById } from '../../../../entity/task/taskSelector';
|
|
8
7
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
9
8
|
import { fetchFileList } from '../../../fileView/fileViewReducer';
|
|
10
|
-
import { updateTaskListOnNewTaskCreationSuccess } from '../../taskListView/taskListReducer';
|
|
11
9
|
import { fetchTaskDetail, initializeTaskToLocalStore, removeTaskDetail, updateEditTaskFetchStatus, } from '../taskDetailReducer';
|
|
12
10
|
export const fetchTaskDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchTaskDetail.match), mergeMap((action) => {
|
|
13
11
|
const { taskId, cacheOverride } = action.payload;
|
|
14
12
|
const taskActions = [];
|
|
15
13
|
const state = state$.value;
|
|
16
|
-
const isTaskListFetched = state.taskListState.fetchState === 'Completed';
|
|
17
14
|
const taskDetail = recordGet(state.taskDetailState.editTaskStateById, taskId, undefined);
|
|
18
15
|
if (cacheOverride === true) {
|
|
19
16
|
taskActions.push(removeTaskDetail(taskId));
|
|
@@ -35,16 +32,6 @@ export const fetchTaskDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
|
|
|
35
32
|
updateTags(response.data.tasks.map((task) => task.tags).flat()),
|
|
36
33
|
initializeTaskToLocalStore(taskId),
|
|
37
34
|
];
|
|
38
|
-
if (isTaskListFetched === true) {
|
|
39
|
-
const taskGroupId = response.data.tasks[0].task_group_ids?.[0];
|
|
40
|
-
if (taskGroupId != null) {
|
|
41
|
-
fetchActions.push(updateTaskListOnNewTaskCreationSuccess({
|
|
42
|
-
taskGroupId,
|
|
43
|
-
task: response.data.tasks[0],
|
|
44
|
-
currentTaskState: getTaskById(state.taskState, taskId),
|
|
45
|
-
}));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
35
|
const fileIds = response.data.tasks[0].file_ids;
|
|
49
36
|
if (fileIds.length > 0) {
|
|
50
37
|
fetchActions.push(fetchFileList(fileIds));
|
|
@@ -6,11 +6,6 @@ import { initialTaskDetail, } from './taskDetail';
|
|
|
6
6
|
export const initialState = {
|
|
7
7
|
newTaskState: initialTaskDetail,
|
|
8
8
|
editTaskStateById: {},
|
|
9
|
-
subTaskCreateStatus: {
|
|
10
|
-
fetchState: 'Not-Started',
|
|
11
|
-
error: undefined,
|
|
12
|
-
},
|
|
13
|
-
subTaskListFetchStatusByParentId: {},
|
|
14
9
|
taskHistoryById: {},
|
|
15
10
|
};
|
|
16
11
|
const taskDetailView = createSlice({
|
|
@@ -55,7 +50,7 @@ const taskDetailView = createSlice({
|
|
|
55
50
|
updateEditTaskFetchStatus(draft, action) {
|
|
56
51
|
const { taskId, fetchState, error } = action.payload;
|
|
57
52
|
draft.editTaskStateById[taskId] = {
|
|
58
|
-
...
|
|
53
|
+
...draft.editTaskStateById[taskId],
|
|
59
54
|
fetchTaskStatus: {
|
|
60
55
|
fetchState,
|
|
61
56
|
error: fetchState === 'Error' ? error : undefined,
|
|
@@ -323,59 +318,10 @@ const taskDetailView = createSlice({
|
|
|
323
318
|
error,
|
|
324
319
|
};
|
|
325
320
|
},
|
|
326
|
-
createSubTask: {
|
|
327
|
-
reducer(draft) {
|
|
328
|
-
draft.subTaskCreateStatus = {
|
|
329
|
-
fetchState: 'In-Progress',
|
|
330
|
-
error: undefined,
|
|
331
|
-
};
|
|
332
|
-
},
|
|
333
|
-
prepare(payload) {
|
|
334
|
-
return { payload };
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
createSubTaskSuccessOrFailure(draft, action) {
|
|
338
|
-
const { fetchState, error } = action.payload;
|
|
339
|
-
draft.subTaskCreateStatus = {
|
|
340
|
-
fetchState,
|
|
341
|
-
error,
|
|
342
|
-
};
|
|
343
|
-
},
|
|
344
|
-
resetSubTaskCreateStatus(draft) {
|
|
345
|
-
draft.subTaskCreateStatus = {
|
|
346
|
-
...initialState.subTaskCreateStatus,
|
|
347
|
-
};
|
|
348
|
-
},
|
|
349
|
-
fetchSubTasks: {
|
|
350
|
-
reducer(draft, action) {
|
|
351
|
-
const { parentTaskId } = action.payload;
|
|
352
|
-
draft.subTaskListFetchStatusByParentId[parentTaskId] = {
|
|
353
|
-
fetchState: 'In-Progress',
|
|
354
|
-
error: undefined,
|
|
355
|
-
};
|
|
356
|
-
},
|
|
357
|
-
prepare(parentTaskId) {
|
|
358
|
-
return { payload: { parentTaskId } };
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
updateSubTasks(draft, action) {
|
|
362
|
-
const { parentTaskId } = action.payload;
|
|
363
|
-
draft.subTaskListFetchStatusByParentId[parentTaskId] = {
|
|
364
|
-
fetchState: 'Completed',
|
|
365
|
-
error: undefined,
|
|
366
|
-
};
|
|
367
|
-
},
|
|
368
|
-
updateSubTasksFetchStatus(draft, action) {
|
|
369
|
-
const { parentTaskId, fetchState, error } = action.payload;
|
|
370
|
-
draft.subTaskListFetchStatusByParentId[parentTaskId] = {
|
|
371
|
-
fetchState,
|
|
372
|
-
error,
|
|
373
|
-
};
|
|
374
|
-
},
|
|
375
321
|
clearTaskDetail(draft) {
|
|
376
322
|
Object.assign(draft, initialState);
|
|
377
323
|
},
|
|
378
324
|
},
|
|
379
325
|
});
|
|
380
|
-
export const { fetchTaskDetailPage, fetchTaskDetail, initializeTaskToLocalStore, updateEditTaskFetchStatus, saveTaskUpdatesToLocalStore, discardTaskUpdatesInLocalStore, saveTaskDetail, archiveTask, archiveTaskSuccessOrFailure, saveTaskSuccessOrFailure,
|
|
326
|
+
export const { fetchTaskDetailPage, fetchTaskDetail, initializeTaskToLocalStore, updateEditTaskFetchStatus, saveTaskUpdatesToLocalStore, discardTaskUpdatesInLocalStore, saveTaskDetail, archiveTask, archiveTaskSuccessOrFailure, saveTaskSuccessOrFailure, deleteTask, removeTaskDetail, deleteTaskSuccessOrFailure, snoozeTask, snoozeTaskSuccessOrFailure, unsnoozeTask, fetchTaskHistory, updateTaskHistory, updateTaskHistoryFetchStatus, clearTaskDetail, updateCreatedTagToLocalStore, updateDeletedTagToLocalStore, } = taskDetailView.actions;
|
|
381
327
|
export default taskDetailView.reducer;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import isEqual from 'lodash/isEqual';
|
|
2
|
-
import {
|
|
2
|
+
import { reduceFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
3
|
import { getClassesByIds } from '../../../entity/class/classSelector';
|
|
4
4
|
import { getFilesByFileIds } from '../../../entity/file/fileSelector';
|
|
5
|
-
import { getTaskById
|
|
5
|
+
import { getTaskById } from '../../../entity/task/taskSelector';
|
|
6
6
|
import { getUserAndUserRole, } from '../../companyView/types/userAndRole';
|
|
7
7
|
import { getFileDeleteStatusById, getFileUpdateNameStatusById, } from '../../fileView/fileViewSelector';
|
|
8
8
|
import { getUserList, } from '../../userListView/userListViewSelector';
|
|
@@ -27,13 +27,8 @@ export const getTaskDetail = (state, taskId) => {
|
|
|
27
27
|
let recurringSourceTaskId = undefined;
|
|
28
28
|
let snoozedUntil = undefined;
|
|
29
29
|
let taskGroupId = undefined;
|
|
30
|
-
let subtasks = [];
|
|
31
30
|
if (taskId != null && sourceTaskDetail != null) {
|
|
32
31
|
const taskEntity = getTaskById(taskState, taskId);
|
|
33
|
-
subtasks =
|
|
34
|
-
taskEntity != null
|
|
35
|
-
? getTasksByIds(taskState, taskEntity.subTasksIds)
|
|
36
|
-
: [];
|
|
37
32
|
const fileIdsInEntity = taskEntity?.fileIds ?? [];
|
|
38
33
|
if (taskEntity != null) {
|
|
39
34
|
createdByUser = getUserAndUserRole(userState, userRoleState, addressState, taskEntity.createdBy);
|
|
@@ -44,27 +39,25 @@ export const getTaskDetail = (state, taskId) => {
|
|
|
44
39
|
taskGroupId = taskEntity.taskGroupIds[0];
|
|
45
40
|
}
|
|
46
41
|
if (fileIdsInEntity.length > 0) {
|
|
47
|
-
fetchStatus =
|
|
42
|
+
fetchStatus = reduceFetchState([
|
|
48
43
|
fileViewState.fetchFilesStatus,
|
|
49
44
|
sourceTaskDetail.fetchTaskStatus,
|
|
50
45
|
userList,
|
|
51
46
|
classListState,
|
|
52
|
-
taskDetailState.subTaskListFetchStatusByParentId[taskId] ?? fetchStatus,
|
|
53
47
|
]);
|
|
54
48
|
}
|
|
55
49
|
else {
|
|
56
|
-
fetchStatus =
|
|
50
|
+
fetchStatus = reduceFetchState([
|
|
57
51
|
sourceTaskDetail.fetchTaskStatus,
|
|
58
52
|
userList,
|
|
59
53
|
classListState,
|
|
60
|
-
taskDetailState.subTaskListFetchStatusByParentId[taskId] ?? fetchStatus,
|
|
61
54
|
]);
|
|
62
55
|
}
|
|
63
56
|
showTaskDetailFormFooter = showFormFooter(sourceTaskDetail.taskDetailLocalData, taskEntity);
|
|
64
57
|
taskHistory = taskDetailState.taskHistoryById[taskId]?.historicEvents ?? [];
|
|
65
58
|
}
|
|
66
59
|
else if (taskId == null) {
|
|
67
|
-
fetchStatus =
|
|
60
|
+
fetchStatus = reduceFetchState([userList, classListState]);
|
|
68
61
|
}
|
|
69
62
|
const { classIds } = classListState;
|
|
70
63
|
const allAccountingClasses = getClassesByIds(classState, {
|
|
@@ -97,7 +90,6 @@ export const getTaskDetail = (state, taskId) => {
|
|
|
97
90
|
showTaskDetailFormFooter,
|
|
98
91
|
snoozedUntil,
|
|
99
92
|
taskGroupId,
|
|
100
|
-
subtasks,
|
|
101
93
|
};
|
|
102
94
|
};
|
|
103
95
|
export const allTaskStatus = [
|
|
@@ -145,16 +137,13 @@ export const allTaskPriority = [
|
|
|
145
137
|
},
|
|
146
138
|
];
|
|
147
139
|
const showFormFooter = (taskDetailLocalData, taskDetailInStore) => {
|
|
148
|
-
if (
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
if (taskDetailLocalData.name !== taskDetailInStore.name ||
|
|
140
|
+
if (taskDetailLocalData.name !== taskDetailInStore?.name ||
|
|
152
141
|
taskDetailLocalData.description !== taskDetailInStore.description ||
|
|
153
142
|
taskDetailLocalData.priority !== taskDetailInStore.priority.code ||
|
|
154
143
|
taskDetailLocalData.status !== taskDetailInStore.status.code ||
|
|
155
144
|
!isEqual(taskDetailInStore.tagIds, taskDetailLocalData.tagIds) ||
|
|
156
|
-
!isEqual(taskDetailLocalData.assignee, taskDetailInStore
|
|
157
|
-
!isEqual(taskDetailLocalData.groupAssignees, taskDetailInStore
|
|
145
|
+
!isEqual(taskDetailLocalData.assignee, taskDetailInStore?.assignees ?? []) ||
|
|
146
|
+
!isEqual(taskDetailLocalData.groupAssignees, taskDetailInStore?.groupAssignees ?? []) ||
|
|
158
147
|
!isEqual(taskDetailLocalData.fileIds, taskDetailInStore.fileIds ?? []) ||
|
|
159
148
|
!isEqual(taskDetailLocalData.dueDate, taskDetailInStore.dueDate) ||
|
|
160
149
|
!isEqual(taskDetailLocalData.type, taskDetailInStore.type) ||
|