From 5ba68e997d6868e0484ed013fc03cfce14a833a0 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Fri, 27 Oct 2023 10:52:26 +0200 Subject: [PATCH] Improve viewbar api (#2233) * create scopes * fix import bug * add useView hook * wip * wip * currentViewId is now retrieved via useView * working on sorts with useView * refactor in progress * refactor in progress * refactor in progress * refactor in progress * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * fix code * fix code * wip * push * Fix issue dependencies * Fix resize --------- Co-authored-by: bosiraphael --- .../tasks/components/PageAddTaskButton.tsx | 12 +- .../tasks/hooks/useCurrentUserDueTaskCount.ts | 2 +- .../activities/tasks/hooks/useTasks.ts | 17 +- .../board/components/CompanyBoard.tsx | 36 +-- .../FilterDropdownCompanySearchSelect.tsx | 21 +- .../components/HooksCompanyBoardEffect.tsx | 86 ++---- ...=> companiesAvailableFieldDefinitions.tsx} | 2 +- .../table/components/CompanyTable.tsx | 121 +++++---- .../table/components/CompanyTableEffect.tsx | 60 +++++ .../components/CompanyTableMockDataEffect.tsx | 5 +- .../table/components/CompanyTableMockMode.tsx | 17 +- .../components/ObjectDataTableEffect.tsx | 19 +- .../metadata/components/ObjectTable.tsx | 20 +- .../hooks/useCreateNewTempCustomObject.ts | 2 +- .../metadata/hooks/useMetadataTableViews.ts | 81 ------ .../metadata/hooks/useSetDataTableData.ts | 10 +- .../FilterDropdownPeopleSearchSelect.tsx | 21 +- .../people/hooks/useSetPeopleDataTable.ts | 10 +- .../people/table/components/PeopleTable.tsx | 105 ++++---- .../data/data-table/components/DataTable.tsx | 2 - .../data-table/components/DataTableEffect.tsx | 52 +--- .../data-table/components/DataTableHeader.tsx | 54 ++-- .../data-table/components/DataTableRow.tsx | 16 +- .../data-table}/hooks/useMoveViewColumns.ts | 0 .../data-table/hooks/useSetDataTableData.ts | 21 +- .../data/data-table/hooks/useTableColumns.ts | 22 +- .../components/TableOptionsDropdown.tsx | 8 +- .../TableOptionsDropdownContent.tsx | 80 ++---- .../TableOptionsDropdown.stories.tsx | 44 ---- .../table-header/components/TableHeader.tsx | 52 ---- .../components/AddFilterFromDetailsButton.tsx | 0 .../components/FilterDropdownButton.tsx | 11 +- .../FilterDropdownDateSearchInput.tsx | 36 +++ .../FilterDropdownEntitySearchInput.tsx | 29 +++ .../FilterDropdownEntitySearchSelect.tsx | 42 +-- .../components/FilterDropdownEntitySelect.tsx | 21 ++ .../components/FilterDropdownFilterSelect.tsx | 35 +-- .../FilterDropdownNumberSearchInput.tsx | 22 +- .../FilterDropdownOperandButton.tsx | 27 ++ .../FilterDropdownOperandSelect.tsx | 33 +-- .../FilterDropdownTextSearchInput.tsx | 33 +-- .../components/GenericEntityFilterChip.tsx | 0 .../components/MultipleFiltersButton.tsx | 39 +++ .../MultipleFiltersDropdownButton.tsx | 0 .../MultipleFiltersDropdownContent.tsx | 27 +- ...ersDropdownFilterOnFilterChangedEffect.tsx | 0 .../SingleEntityFilterDropdownButton.tsx | 39 +-- .../constants/FilterDropdownId.ts | 0 .../modules/ui/data/filter/hooks/useFilter.ts | 54 ++++ .../filter/hooks/useFilterCurrentlyEdited.ts | 13 + .../ui/data/filter/hooks/useFilterStates.ts | 64 +++++ .../ui/data/filter/scopes/FilterScope.tsx | 28 ++ .../init-effect/FilterScopeInitEffect.tsx | 25 ++ .../FilterScopeInternalContext.ts | 9 + .../states/availableFiltersScopedState.ts | 9 + ...lterDefinitionUsedInDropdownScopedState.ts | 9 + .../filterDropdownSearchInputScopedState.ts | 6 + ...lterDropdownSelectedEntityIdScopedState.ts | 8 + ...ropdownOperandSelectUnfoldedScopedState.ts | 7 + .../isFilterDropdownUnfoldedScopedState.ts | 6 + .../states/selectedFiltersScopedState.ts | 8 + .../selectedOperandInDropdownScopedState.ts | 8 + .../selectors/filtersWhereScopedSelector.ts | 8 +- .../data/{view-bar => filter}/types/Filter.ts | 0 .../types/FilterDefinition.ts | 0 .../types/FilterDefinitionByEntity.ts | 0 .../types/FilterOperand.ts | 0 .../{view-bar => filter}/types/FilterType.ts | 0 .../types/FiltersHotkeyScope.ts | 0 .../utils/getOperandLabel.ts | 0 .../utils/getOperandsForFilterType.ts | 0 .../utils/turnFilterIntoWhereClause.ts | 0 .../components/SortDropdownButton.tsx | 44 +--- .../constants/SortDropdownId.ts | 0 .../src/modules/ui/data/sort/hooks/useSort.ts | 36 +++ .../ui/data/sort/hooks/useSortStates.ts | 23 ++ .../modules/ui/data/sort/scopes/SortScope.tsx | 33 +++ .../init-effect/SortScopeInitEffect.tsx | 25 ++ .../SortScopeInternalContext.ts | 13 + .../sort/states/availableSortsScopedState.ts | 8 + .../sort/states/isSortSelectedScopedState.ts | 6 + .../ui/data/{view-bar => sort}/types/Sort.ts | 0 .../types/SortDefinition.ts | 0 .../{view-bar => sort}/types/SortDirection.ts | 0 .../{view-bar => sort}/types/interface.ts | 0 .../data/{view-bar => sort}/utils/helpers.ts | 0 .../FilterDropdownDateSearchInput.tsx | 51 ---- .../FilterDropdownEntitySearchInput.tsx | 44 ---- .../components/FilterDropdownEntitySelect.tsx | 28 -- .../FilterDropdownOperandButton.tsx | 39 --- .../components/MultipleFiltersButton.tsx | 59 ----- .../components/UpdateViewButtonGroup.tsx | 138 ---------- .../ui/data/view-bar/components/ViewBar.tsx | 65 ----- .../data/view-bar/contexts/ViewBarContext.ts | 20 -- .../hooks/useFilterCurrentlyEdited.ts | 28 -- .../ui/data/view-bar/hooks/useRemoveFilter.ts | 25 -- .../ui/data/view-bar/hooks/useRemoveView.ts | 35 --- .../ui/data/view-bar/hooks/useUpsertView.ts | 109 -------- .../data/view-bar/hooks/useViewBarContext.ts | 7 - .../states/availableFiltersScopedState.ts | 11 - .../states/availableSortsScopedState.ts | 8 - .../states/currentViewIdScopedState.ts | 6 - .../states/entityCountInCurrentViewState.ts | 6 - ...lterDefinitionUsedInDropdownScopedState.ts | 11 - .../filterDropdownSearchInputScopedState.ts | 6 - ...lterDropdownSelectedEntityIdScopedState.ts | 9 - .../view-bar/states/filtersScopedState.ts | 8 - ...ropdownOperandSelectUnfoldedScopedState.ts | 9 - .../isFilterDropdownUnfoldedScopedState.ts | 6 - .../states/isViewBarExpandedScopedState.ts | 6 - .../states/savedFiltersFamilyState.ts | 10 - .../view-bar/states/savedSortsFamilyState.ts | 8 - .../selectedOperandInDropdownScopedState.ts | 11 - .../canPersistFiltersScopedFamilySelector.ts | 23 -- .../canPersistSortsScopedFamilySelector.ts | 23 -- .../savedFiltersByKeyFamilySelector.ts | 15 -- .../selectors/savedFiltersFamilySelector.ts | 11 - .../savedSortsByKeyFamilySelector.ts | 15 -- .../selectors/savedSortsFamilySelector.ts | 11 - .../selectors/sortsOrderByScopedSelector.ts | 16 -- .../data/view-bar/states/sortsScopedState.ts | 8 - .../data/view-bar/states/viewEditModeState.ts | 9 - .../data/view-bar/states/viewsScopedState.ts | 8 - .../layout/board/components/BoardHeader.tsx | 123 --------- .../board/components/BoardOptionsDropdown.tsx | 8 +- .../BoardOptionsDropdownContent.tsx | 85 +++--- .../layout/board/components/EntityBoard.tsx | 8 +- .../BoardOptionsDropdown.stories.tsx | 53 ---- .../layout/board/hooks/useBoardCardFields.ts | 2 +- .../ui/layout/board/hooks/useBoardColumns.ts | 2 +- .../ui/layout/board/types/BoardOptions.ts | 4 +- .../ui/layout/dropdown/hooks/useDropdown.ts | 2 +- .../hooks/useRecoilScopedFamilyState.ts | 12 +- .../hooks/useSetRecoilScopedFamilyState.ts | 27 ++ .../hooks/useSetRecoilScopedStateV2.ts | 14 + .../FilterDropdownUserSearchSelect.tsx | 26 +- .../components/SortOrFilterChip.tsx | 0 .../components/UpdateViewButtonGroup.tsx | 84 ++++++ .../src/modules/views/components/ViewBar.tsx | 82 ++++++ .../components/ViewBarDetails.tsx | 99 ++----- .../views/components/ViewBarEffect.tsx | 218 ++++++++++++++++ .../ViewFieldsVisibilityDropdownSection.tsx | 0 .../components/ViewsDropdownButton.tsx | 88 ++----- .../constants/ViewsDropdownId.ts | 0 .../views/hooks/internal/useViewFields.ts | 121 +++++++++ .../views/hooks/internal/useViewFilters.ts | 165 ++++++++++++ .../views/hooks/internal/useViewSorts.ts | 157 +++++++++++ .../modules/views/hooks/internal/useViews.ts | 67 +++++ .../modules/views/hooks/useBoardViewFields.ts | 167 ------------ .../src/modules/views/hooks/useBoardViews.ts | 77 ------ .../modules/views/hooks/useRemoveFilter.ts | 15 ++ .../modules/views/hooks/useTableViewFields.ts | 183 ------------- .../src/modules/views/hooks/useTableViews.ts | 83 ------ .../hooks/useUpsertFilter.ts | 17 +- front/src/modules/views/hooks/useView.ts | 189 ++++++++++++++ .../src/modules/views/hooks/useViewFilters.ts | 178 ------------- .../views/hooks/useViewInternalStates.ts | 244 ++++++++++++++++++ front/src/modules/views/hooks/useViewSorts.ts | 172 ------------ .../src/modules/views/hooks/useViewStates.ts | 138 ++++++++++ front/src/modules/views/hooks/useViews.ts | 102 -------- front/src/modules/views/scopes/ViewScope.tsx | 43 +++ .../init-effect/ViewScopeInitEffect.tsx | 46 ++++ .../ViewScopeInternalContext.ts | 7 + .../states/availableFieldsScopedState.ts | 10 + .../states/availableFiltersScopedState.ts | 9 + .../views/states/availableSortsScopedState.ts | 7 + .../currentViewFieldsScopedFamilyState.ts | 11 + .../currentViewFiltersScopedFamilyState.ts | 10 + .../views/states/currentViewIdScopedState.ts | 6 + .../currentViewSortsScopedFamilyState.ts | 10 + .../entityCountInCurrentViewScopedState.ts | 6 + .../states/isViewBarExpandedScopedState.ts | 6 + .../views/states/noneScopedFamilyState.ts | 6 + .../states/onViewFieldsChangeScopedState.ts | 11 + .../states/onViewFiltersChangeScopedState.ts | 9 + .../states/onViewSortsChangeScopedState.ts | 9 + .../savedViewFieldsScopedFamilyState.ts | 11 + .../savedViewFiltersScopedFamilyState.ts | 10 + .../states/savedViewSortsScopedFamilyState.ts | 10 + ...nPersistViewFiltersScopedFamilySelector.ts | 31 +++ ...canPersistViewSortsScopedFamilySelector.ts | 31 +++ .../selectors/currentViewScopedSelector.ts | 5 +- ...entViewSortsOrderByScopedFamilySelector.ts | 26 ++ ...savedViewFieldByKeyScopedFamilySelector.ts | 32 +++ ...vedViewFiltersByKeyScopedFamilySelector.ts | 25 ++ ...savedViewSortsByKeyScopedFamilySelector.ts | 25 ++ .../selectors/savedViewSortsFamilySelector.ts | 16 ++ .../selectors/viewsByIdScopedSelector.ts | 5 +- .../views/states/viewEditModeScopedState.ts | 8 + .../views/states/viewObjectIdScopeState.ts | 6 + .../views/states/viewTypeScopedState.ts | 7 + .../modules/views/states/viewsScopedState.ts | 8 + .../{ui/data/view-bar => views}/types/View.ts | 0 .../types/ViewFieldForVisibility.ts | 0 .../types/ViewsHotkeyScope.ts | 0 .../src/pages/companies/companies-filters.tsx | 9 +- front/src/pages/companies/companies-sorts.tsx | 2 +- .../opportunities/opportunities-filters.tsx | 2 +- .../opportunities/opportunities-sorts.tsx | 2 +- front/src/pages/people/people-filters.tsx | 2 +- front/src/pages/people/people-sorts.tsx | 4 +- front/src/pages/tasks/Tasks.tsx | 49 ++-- front/src/pages/tasks/TasksEffect.tsx | 19 +- front/src/pages/tasks/tasks-filters.tsx | 7 +- front/src/testing/mock-data/companies.ts | 27 +- 205 files changed, 3092 insertions(+), 3249 deletions(-) rename front/src/modules/companies/constants/{companiesAvailableColumnDefinitions.tsx => companiesAvailableFieldDefinitions.tsx} (98%) create mode 100644 front/src/modules/companies/table/components/CompanyTableEffect.tsx delete mode 100644 front/src/modules/metadata/hooks/useMetadataTableViews.ts rename front/src/modules/{views => ui/data/data-table}/hooks/useMoveViewColumns.ts (100%) delete mode 100644 front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx delete mode 100644 front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx rename front/src/modules/ui/data/{view-bar => filter}/components/AddFilterFromDetailsButton.tsx (100%) rename front/src/modules/ui/data/{view-bar => filter}/components/FilterDropdownButton.tsx (63%) create mode 100644 front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx create mode 100644 front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx rename front/src/modules/ui/data/{view-bar => filter}/components/FilterDropdownEntitySearchSelect.tsx (70%) create mode 100644 front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx rename front/src/modules/ui/data/{view-bar => filter}/components/FilterDropdownFilterSelect.tsx (50%) rename front/src/modules/ui/data/{view-bar => filter}/components/FilterDropdownNumberSearchInput.tsx (54%) create mode 100644 front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx rename front/src/modules/ui/data/{view-bar => filter}/components/FilterDropdownOperandSelect.tsx (62%) rename front/src/modules/ui/data/{view-bar => filter}/components/FilterDropdownTextSearchInput.tsx (53%) rename front/src/modules/ui/data/{view-bar => filter}/components/GenericEntityFilterChip.tsx (100%) create mode 100644 front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx rename front/src/modules/ui/data/{view-bar => filter}/components/MultipleFiltersDropdownButton.tsx (100%) rename front/src/modules/ui/data/{view-bar => filter}/components/MultipleFiltersDropdownContent.tsx (67%) rename front/src/modules/ui/data/{view-bar => filter}/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx (100%) rename front/src/modules/ui/data/{view-bar => filter}/components/SingleEntityFilterDropdownButton.tsx (62%) rename front/src/modules/ui/data/{view-bar => filter}/constants/FilterDropdownId.ts (100%) create mode 100644 front/src/modules/ui/data/filter/hooks/useFilter.ts create mode 100644 front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts create mode 100644 front/src/modules/ui/data/filter/hooks/useFilterStates.ts create mode 100644 front/src/modules/ui/data/filter/scopes/FilterScope.tsx create mode 100644 front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx create mode 100644 front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts create mode 100644 front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts create mode 100644 front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts rename front/src/modules/ui/data/{view-bar => filter}/states/selectors/filtersWhereScopedSelector.ts (55%) rename front/src/modules/ui/data/{view-bar => filter}/types/Filter.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/types/FilterDefinition.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/types/FilterDefinitionByEntity.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/types/FilterOperand.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/types/FilterType.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/types/FiltersHotkeyScope.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/utils/getOperandLabel.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/utils/getOperandsForFilterType.ts (100%) rename front/src/modules/ui/data/{view-bar => filter}/utils/turnFilterIntoWhereClause.ts (100%) rename front/src/modules/ui/data/{view-bar => sort}/components/SortDropdownButton.tsx (74%) rename front/src/modules/ui/data/{view-bar => sort}/constants/SortDropdownId.ts (100%) create mode 100644 front/src/modules/ui/data/sort/hooks/useSort.ts create mode 100644 front/src/modules/ui/data/sort/hooks/useSortStates.ts create mode 100644 front/src/modules/ui/data/sort/scopes/SortScope.tsx create mode 100644 front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx create mode 100644 front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts create mode 100644 front/src/modules/ui/data/sort/states/availableSortsScopedState.ts create mode 100644 front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts rename front/src/modules/ui/data/{view-bar => sort}/types/Sort.ts (100%) rename front/src/modules/ui/data/{view-bar => sort}/types/SortDefinition.ts (100%) rename front/src/modules/ui/data/{view-bar => sort}/types/SortDirection.ts (100%) rename front/src/modules/ui/data/{view-bar => sort}/types/interface.ts (100%) rename front/src/modules/ui/data/{view-bar => sort}/utils/helpers.ts (100%) delete mode 100644 front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx delete mode 100644 front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx delete mode 100644 front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx delete mode 100644 front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx delete mode 100644 front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx delete mode 100644 front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx delete mode 100644 front/src/modules/ui/data/view-bar/components/ViewBar.tsx delete mode 100644 front/src/modules/ui/data/view-bar/contexts/ViewBarContext.ts delete mode 100644 front/src/modules/ui/data/view-bar/hooks/useFilterCurrentlyEdited.ts delete mode 100644 front/src/modules/ui/data/view-bar/hooks/useRemoveFilter.ts delete mode 100644 front/src/modules/ui/data/view-bar/hooks/useRemoveView.ts delete mode 100644 front/src/modules/ui/data/view-bar/hooks/useUpsertView.ts delete mode 100644 front/src/modules/ui/data/view-bar/hooks/useViewBarContext.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/availableFiltersScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/availableSortsScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/currentViewIdScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/entityCountInCurrentViewState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/filterDropdownSearchInputScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/filtersScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/isFilterDropdownUnfoldedScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/isViewBarExpandedScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/savedFiltersFamilyState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/savedSortsFamilyState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectedOperandInDropdownScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/canPersistFiltersScopedFamilySelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/canPersistSortsScopedFamilySelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/savedFiltersByKeyFamilySelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/savedFiltersFamilySelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/savedSortsByKeyFamilySelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/savedSortsFamilySelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/selectors/sortsOrderByScopedSelector.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/sortsScopedState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/viewEditModeState.ts delete mode 100644 front/src/modules/ui/data/view-bar/states/viewsScopedState.ts delete mode 100644 front/src/modules/ui/layout/board/components/BoardHeader.tsx delete mode 100644 front/src/modules/ui/layout/board/components/__stories__/BoardOptionsDropdown.stories.tsx create mode 100644 front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedFamilyState.ts create mode 100644 front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedStateV2.ts rename front/src/modules/{ui/data/view-bar => views}/components/SortOrFilterChip.tsx (100%) create mode 100644 front/src/modules/views/components/UpdateViewButtonGroup.tsx create mode 100644 front/src/modules/views/components/ViewBar.tsx rename front/src/modules/{ui/data/view-bar => views}/components/ViewBarDetails.tsx (58%) create mode 100644 front/src/modules/views/components/ViewBarEffect.tsx rename front/src/modules/{ui/data/view-bar => views}/components/ViewFieldsVisibilityDropdownSection.tsx (100%) rename front/src/modules/{ui/data/view-bar => views}/components/ViewsDropdownButton.tsx (61%) rename front/src/modules/{ui/data/view-bar => views}/constants/ViewsDropdownId.ts (100%) create mode 100644 front/src/modules/views/hooks/internal/useViewFields.ts create mode 100644 front/src/modules/views/hooks/internal/useViewFilters.ts create mode 100644 front/src/modules/views/hooks/internal/useViewSorts.ts create mode 100644 front/src/modules/views/hooks/internal/useViews.ts delete mode 100644 front/src/modules/views/hooks/useBoardViewFields.ts delete mode 100644 front/src/modules/views/hooks/useBoardViews.ts create mode 100644 front/src/modules/views/hooks/useRemoveFilter.ts delete mode 100644 front/src/modules/views/hooks/useTableViewFields.ts delete mode 100644 front/src/modules/views/hooks/useTableViews.ts rename front/src/modules/{ui/data/view-bar => views}/hooks/useUpsertFilter.ts (51%) create mode 100644 front/src/modules/views/hooks/useView.ts delete mode 100644 front/src/modules/views/hooks/useViewFilters.ts create mode 100644 front/src/modules/views/hooks/useViewInternalStates.ts delete mode 100644 front/src/modules/views/hooks/useViewSorts.ts create mode 100644 front/src/modules/views/hooks/useViewStates.ts delete mode 100644 front/src/modules/views/hooks/useViews.ts create mode 100644 front/src/modules/views/scopes/ViewScope.tsx create mode 100644 front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx create mode 100644 front/src/modules/views/scopes/scope-internal-context/ViewScopeInternalContext.ts create mode 100644 front/src/modules/views/states/availableFieldsScopedState.ts create mode 100644 front/src/modules/views/states/availableFiltersScopedState.ts create mode 100644 front/src/modules/views/states/availableSortsScopedState.ts create mode 100644 front/src/modules/views/states/currentViewFieldsScopedFamilyState.ts create mode 100644 front/src/modules/views/states/currentViewFiltersScopedFamilyState.ts create mode 100644 front/src/modules/views/states/currentViewIdScopedState.ts create mode 100644 front/src/modules/views/states/currentViewSortsScopedFamilyState.ts create mode 100644 front/src/modules/views/states/entityCountInCurrentViewScopedState.ts create mode 100644 front/src/modules/views/states/isViewBarExpandedScopedState.ts create mode 100644 front/src/modules/views/states/noneScopedFamilyState.ts create mode 100644 front/src/modules/views/states/onViewFieldsChangeScopedState.ts create mode 100644 front/src/modules/views/states/onViewFiltersChangeScopedState.ts create mode 100644 front/src/modules/views/states/onViewSortsChangeScopedState.ts create mode 100644 front/src/modules/views/states/savedViewFieldsScopedFamilyState.ts create mode 100644 front/src/modules/views/states/savedViewFiltersScopedFamilyState.ts create mode 100644 front/src/modules/views/states/savedViewSortsScopedFamilyState.ts create mode 100644 front/src/modules/views/states/selectors/canPersistViewFiltersScopedFamilySelector.ts create mode 100644 front/src/modules/views/states/selectors/canPersistViewSortsScopedFamilySelector.ts rename front/src/modules/{ui/data/view-bar => views}/states/selectors/currentViewScopedSelector.ts (79%) create mode 100644 front/src/modules/views/states/selectors/currentViewSortsOrderByScopedFamilySelector.ts create mode 100644 front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts create mode 100644 front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts create mode 100644 front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts create mode 100644 front/src/modules/views/states/selectors/savedViewSortsFamilySelector.ts rename front/src/modules/{ui/data/view-bar => views}/states/selectors/viewsByIdScopedSelector.ts (73%) create mode 100644 front/src/modules/views/states/viewEditModeScopedState.ts create mode 100644 front/src/modules/views/states/viewObjectIdScopeState.ts create mode 100644 front/src/modules/views/states/viewTypeScopedState.ts create mode 100644 front/src/modules/views/states/viewsScopedState.ts rename front/src/modules/{ui/data/view-bar => views}/types/View.ts (100%) rename front/src/modules/{ui/data/view-bar => views}/types/ViewFieldForVisibility.ts (100%) rename front/src/modules/{ui/data/view-bar => views}/types/ViewsHotkeyScope.ts (100%) diff --git a/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx b/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx index fdfe3e5cf..f878b5bd9 100644 --- a/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx +++ b/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx @@ -1,19 +1,13 @@ import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; -import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; +import { useFilter } from '@/ui/data/filter/hooks/useFilter'; import { PageAddButton } from '@/ui/layout/page/PageAddButton'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { ActivityType } from '~/generated/graphql'; export const PageAddTaskButton = () => { + const { selectedFilters } = useFilter(); const openCreateActivity = useOpenCreateActivityDrawer(); - const filters = useRecoilScopedValue( - filtersScopedState, - TasksRecoilScopeContext, - ); - - const assigneeIdFilter = filters.find( + const assigneeIdFilter = selectedFilters.find( (filter) => filter.key === 'assigneeId', ); diff --git a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts index 2f140d3f1..5aa2a8427 100644 --- a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts +++ b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts @@ -2,7 +2,7 @@ import { DateTime } from 'luxon'; import { useRecoilState } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; -import { turnFilterIntoWhereClause } from '@/ui/data/view-bar/utils/turnFilterIntoWhereClause'; +import { turnFilterIntoWhereClause } from '@/ui/data/filter/utils/turnFilterIntoWhereClause'; import { ActivityType, useGetActivitiesQuery, diff --git a/front/src/modules/activities/tasks/hooks/useTasks.ts b/front/src/modules/activities/tasks/hooks/useTasks.ts index fbba10c1c..7db8f20cd 100644 --- a/front/src/modules/activities/tasks/hooks/useTasks.ts +++ b/front/src/modules/activities/tasks/hooks/useTasks.ts @@ -1,18 +1,13 @@ import { DateTime } from 'luxon'; -import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext'; import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; -import { turnFilterIntoWhereClause } from '@/ui/data/view-bar/utils/turnFilterIntoWhereClause'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; +import { useFilter } from '@/ui/data/filter/hooks/useFilter'; +import { turnFilterIntoWhereClause } from '@/ui/data/filter/utils/turnFilterIntoWhereClause'; import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql'; import { parseDate } from '~/utils/date-utils'; export const useTasks = (entity?: ActivityTargetableEntity) => { - const [filters] = useRecoilScopedState( - filtersScopedState, - TasksRecoilScopeContext, - ); + const { selectedFilters } = useFilter(); const whereFilters = entity ? { @@ -27,7 +22,7 @@ export const useTasks = (entity?: ActivityTargetableEntity) => { } : Object.assign( {}, - ...filters.map((filter) => { + ...selectedFilters.map((filter) => { return turnFilterIntoWhereClause(filter); }), ); @@ -40,7 +35,7 @@ export const useTasks = (entity?: ActivityTargetableEntity) => { ...whereFilters, }, }, - skip: !entity && filters.length === 0, + skip: !entity && selectedFilters.length === 0, }); const { data: incompleteTaskData } = useGetActivitiesQuery({ @@ -51,7 +46,7 @@ export const useTasks = (entity?: ActivityTargetableEntity) => { ...whereFilters, }, }, - skip: !entity && filters.length === 0, + skip: !entity && selectedFilters.length === 0, }); const todayOrPreviousTasks = incompleteTaskData?.findManyActivities.filter( diff --git a/front/src/modules/companies/board/components/CompanyBoard.tsx b/front/src/modules/companies/board/components/CompanyBoard.tsx index f4aa76ac3..421652dd6 100644 --- a/front/src/modules/companies/board/components/CompanyBoard.tsx +++ b/front/src/modules/companies/board/components/CompanyBoard.tsx @@ -1,13 +1,10 @@ import { BoardContext } from '@/companies/states/contexts/BoardContext'; -import { pipelineAvailableFieldDefinitions } from '@/pipeline/constants/pipelineAvailableFieldDefinitions'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; import { EntityBoard, EntityBoardProps, } from '@/ui/layout/board/components/EntityBoard'; import { EntityBoardActionBar } from '@/ui/layout/board/components/EntityBoardActionBar'; import { EntityBoardContextMenu } from '@/ui/layout/board/components/EntityBoardContextMenu'; -import { useBoardViews } from '@/views/hooks/useBoardViews'; import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions'; import { HooksCompanyBoardEffect } from '../../components/HooksCompanyBoardEffect'; @@ -23,15 +20,6 @@ export const CompanyBoard = ({ onColumnDelete, onEditColumnTitle, }: CompanyBoardProps) => { - // TODO: we can store objectId and fieldDefinitions in the ViewBarContext - // And then use the useBoardViews web-hook wherever we need it in the board - const { createView, deleteView, submitCurrentView, updateView } = - useBoardViews({ - objectId: 'company', - RecoilScopeContext: CompanyBoardRecoilScopeContext, - fieldDefinitions: pipelineAvailableFieldDefinitions, - }); - return ( <> - - - + + diff --git a/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx b/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx index 87cdb8046..8964c8383 100644 --- a/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx +++ b/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx @@ -1,24 +1,11 @@ -import { FilterDropdownEntitySearchSelect } from '@/ui/data/view-bar/components/FilterDropdownEntitySearchSelect'; -import { useViewBarContext } from '@/ui/data/view-bar/hooks/useViewBarContext'; -import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState'; -import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; +import { FilterDropdownEntitySearchSelect } from '@/ui/data/filter/components/FilterDropdownEntitySearchSelect'; +import { useFilter } from '@/ui/data/filter/hooks/useFilter'; import { useFilteredSearchCompanyQuery } from '../hooks/useFilteredSearchCompanyQuery'; export const FilterDropdownCompanySearchSelect = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const filterDropdownSearchInput = useRecoilScopedValue( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - - const [filterDropdownSelectedEntityId] = useRecoilScopedState( - filterDropdownSelectedEntityIdScopedState, - ViewBarRecoilScopeContext, - ); + const { filterDropdownSearchInput, filterDropdownSelectedEntityId } = + useFilter(); const usersForSelect = useFilteredSearchCompanyQuery({ searchFilter: filterDropdownSearchInput, diff --git a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx index cdb7eed83..c1a1ad743 100644 --- a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx +++ b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx @@ -1,23 +1,13 @@ import { useEffect, useMemo } from 'react'; import { useSearchParams } from 'react-router-dom'; -import { useRecoilCallback, useRecoilState } from 'recoil'; +import { useRecoilState } from 'recoil'; -import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState'; -import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState'; -import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState'; -import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; -import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState'; -import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState'; -import { sortsOrderByScopedSelector } from '@/ui/data/view-bar/states/selectors/sortsOrderByScopedSelector'; -import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState'; -import { turnFilterIntoWhereClause } from '@/ui/data/view-bar/utils/turnFilterIntoWhereClause'; +import { turnFilterIntoWhereClause } from '@/ui/data/filter/utils/turnFilterIntoWhereClause'; import { useBoardActionBarEntries } from '@/ui/layout/board/hooks/useBoardActionBarEntries'; import { useBoardContextMenuEntries } from '@/ui/layout/board/hooks/useBoardContextMenuEntries'; import { isBoardLoadedState } from '@/ui/layout/board/states/isBoardLoadedState'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; +import { useView } from '@/views/hooks/useView'; +import { useViewInternalStates } from '@/views/hooks/useViewInternalStates'; import { Pipeline, PipelineProgressableType, @@ -29,35 +19,25 @@ import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBo import { useUpdateCompanyBoardCardIds } from '../hooks/useUpdateBoardCardIds'; import { useUpdateCompanyBoard } from '../hooks/useUpdateCompanyBoardColumns'; -import { CompanyBoardRecoilScopeContext } from '../states/recoil-scope-contexts/CompanyBoardRecoilScopeContext'; export const HooksCompanyBoardEffect = () => { - const [, setAvailableFilters] = useRecoilScopedState( - availableFiltersScopedState, - CompanyBoardRecoilScopeContext, - ); + const { + setAvailableFilters, + setAvailableSorts, + setEntityCountInCurrentView, + setCurrentViewId, + } = useView(); - const [, setAvailableSorts] = useRecoilScopedState( - availableSortsScopedState, - CompanyBoardRecoilScopeContext, - ); - - const [, setEntityCountInCurrentView] = useRecoilState( - entityCountInCurrentViewState, - ); + const { currentViewFilters, currentViewSortsOrderBy } = + useViewInternalStates(); useEffect(() => { setAvailableFilters(opportunitiesBoardOptions.filters); - setAvailableSorts(opportunitiesBoardOptions.sorts); - }); + setAvailableSorts?.(opportunitiesBoardOptions.sorts); + }, [setAvailableFilters, setAvailableSorts]); const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState); - const filters = useRecoilScopedValue( - filtersScopedState, - CompanyBoardRecoilScopeContext, - ); - const updateCompanyBoard = useUpdateCompanyBoard(); const { data: pipelineData, loading: loadingGetPipelines } = @@ -77,18 +57,14 @@ export const HooksCompanyBoardEffect = () => { ?.map((pipelineStage) => pipelineStage.id) .flat(); - const sortsOrderBy = useRecoilScopedValue( - sortsOrderByScopedSelector, - CompanyBoardRecoilScopeContext, - ); const whereFilters = useMemo(() => { return { AND: [ { pipelineStageId: { in: pipelineStageIds } }, - ...filters.map(turnFilterIntoWhereClause), + ...(currentViewFilters?.map(turnFilterIntoWhereClause) || []), ], }; - }, [filters, pipelineStageIds]) as any; + }, [currentViewFilters, pipelineStageIds]) as any; const updateCompanyBoardCardIds = useUpdateCompanyBoardCardIds(); @@ -96,7 +72,7 @@ export const HooksCompanyBoardEffect = () => { useGetPipelineProgressQuery({ variables: { where: whereFilters, - orderBy: sortsOrderBy, + orderBy: currentViewSortsOrderBy, }, onCompleted: (data) => { const pipelineProgresses = data?.findManyPipelineProgress || []; @@ -123,30 +99,6 @@ export const HooksCompanyBoardEffect = () => { }); const [searchParams] = useSearchParams(); - const boardRecoilScopeId = useRecoilScopeId(CompanyBoardRecoilScopeContext); - const handleViewSelect = useRecoilCallback( - ({ set, snapshot }) => - async (viewId: string) => { - const currentView = await snapshot.getPromise( - currentViewIdScopedState(boardRecoilScopeId), - ); - if (currentView === viewId) { - return; - } - - const savedFilters = await snapshot.getPromise( - savedFiltersFamilyState(viewId), - ); - const savedSorts = await snapshot.getPromise( - savedSortsFamilyState(viewId), - ); - - set(filtersScopedState(boardRecoilScopeId), savedFilters); - set(sortsScopedState(boardRecoilScopeId), savedSorts); - set(currentViewIdScopedState(boardRecoilScopeId), viewId); - }, - [boardRecoilScopeId], - ); const loading = loadingGetPipelines || loadingGetPipelineProgress || loadingGetCompanies; @@ -158,7 +110,7 @@ export const HooksCompanyBoardEffect = () => { if (!loading && pipeline && pipelineProgresses && companiesData) { const viewId = searchParams.get('view'); if (viewId) { - handleViewSelect(viewId); + //setCurrentViewId(viewId); } setActionBarEntries(); setContextMenuEntries(); @@ -174,8 +126,8 @@ export const HooksCompanyBoardEffect = () => { setActionBarEntries, setContextMenuEntries, searchParams, - handleViewSelect, setEntityCountInCurrentView, + setCurrentViewId, ]); return <>; diff --git a/front/src/modules/companies/constants/companiesAvailableColumnDefinitions.tsx b/front/src/modules/companies/constants/companiesAvailableFieldDefinitions.tsx similarity index 98% rename from front/src/modules/companies/constants/companiesAvailableColumnDefinitions.tsx rename to front/src/modules/companies/constants/companiesAvailableFieldDefinitions.tsx index d034fb6aa..978807852 100644 --- a/front/src/modules/companies/constants/companiesAvailableColumnDefinitions.tsx +++ b/front/src/modules/companies/constants/companiesAvailableFieldDefinitions.tsx @@ -25,7 +25,7 @@ import { import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect'; import { User } from '~/generated/graphql'; -export const companiesAvailableColumnDefinitions: ColumnDefinition[] = +export const companiesAvailableFieldDefinitions: ColumnDefinition[] = [ { key: 'name', diff --git a/front/src/modules/companies/table/components/CompanyTable.tsx b/front/src/modules/companies/table/components/CompanyTable.tsx index 453e357c6..dbe83f876 100644 --- a/front/src/modules/companies/table/components/CompanyTable.tsx +++ b/front/src/modules/companies/table/components/CompanyTable.tsx @@ -1,41 +1,39 @@ -import { companiesAvailableColumnDefinitions } from '@/companies/constants/companiesAvailableColumnDefinitions'; +import styled from '@emotion/styled'; + import { getCompaniesOptimisticEffectDefinition } from '@/companies/graphql/optimistic-effect-definitions/getCompaniesOptimisticEffectDefinition'; import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries'; import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries'; -import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport'; import { DataTable } from '@/ui/data/data-table/components/DataTable'; import { DataTableEffect } from '@/ui/data/data-table/components/DataTableEffect'; import { TableContext } from '@/ui/data/data-table/contexts/TableContext'; import { useUpsertDataTableItem } from '@/ui/data/data-table/hooks/useUpsertDataTableItem'; -import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; -import { useTableViews } from '@/views/hooks/useTableViews'; +import { TableOptionsDropdown } from '@/ui/data/data-table/options/components/TableOptionsDropdown'; +import { TableOptionsHotkeyScope } from '@/ui/data/data-table/types/TableOptionsHotkeyScope'; +import { ViewBar } from '@/views/components/ViewBar'; +import { ViewBarEffect } from '@/views/components/ViewBarEffect'; +import { useViewFields } from '@/views/hooks/internal/useViewFields'; +import { useView } from '@/views/hooks/useView'; +import { ViewScope } from '@/views/scopes/ViewScope'; import { UpdateOneCompanyMutationVariables, useGetCompaniesQuery, useGetWorkspaceMembersLazyQuery, useUpdateOneCompanyMutation, } from '~/generated/graphql'; -import { companiesFilters } from '~/pages/companies/companies-filters'; +import { companyAvailableFilters } from '~/pages/companies/companies-filters'; import { companyAvailableSorts } from '~/pages/companies/companies-sorts'; +import CompanyTableEffect from './CompanyTableEffect'; + export const CompanyTable = () => { + const tableViewScopeId = 'company-table'; + const [updateEntityMutation] = useUpdateOneCompanyMutation(); const upsertDataTableItem = useUpsertDataTableItem(); const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery(); - const { - createView, - deleteView, - persistColumns, - submitCurrentView, - updateView, - } = useTableViews({ - objectId: 'company', - columnDefinitions: companiesAvailableColumnDefinitions, - }); - - const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport(); + const { persistViewFields } = useViewFields(tableViewScopeId); + const { setCurrentViewFields } = useView({ viewScopeId: tableViewScopeId }); const { setContextMenuEntries } = useCompanyTableContextMenuEntries(); const { setActionBarEntries } = useCompanyTableActionBarEntries(); @@ -69,38 +67,61 @@ export const CompanyTable = () => { }); }; + const StyledContainer = styled.div` + display: flex; + flex-direction: column; + height: 100%; + overflow: auto; + `; + return ( - - - - updateCompany(variables)} - /> - - + {}} + onViewSortsChange={() => {}} + onViewFiltersChange={() => {}} + > + + { + setCurrentViewFields?.(columns); + persistViewFields(columns); + }, + }} + > + + + + } + optionsDropdownScopeId="table-dropdown-option" + /> + + + + updateCompany(variables)} + /> + + + ); }; diff --git a/front/src/modules/companies/table/components/CompanyTableEffect.tsx b/front/src/modules/companies/table/components/CompanyTableEffect.tsx new file mode 100644 index 000000000..90a272988 --- /dev/null +++ b/front/src/modules/companies/table/components/CompanyTableEffect.tsx @@ -0,0 +1,60 @@ +import { useEffect } from 'react'; + +import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions'; +import { availableTableColumnsScopedState } from '@/ui/data/data-table/states/availableTableColumnsScopedState'; +import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; +import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState'; +import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; +import { useView } from '@/views/hooks/useView'; +import { useViewInternalStates } from '@/views/hooks/useViewInternalStates'; +import { ViewType } from '~/generated/graphql'; +import { companyAvailableFilters } from '~/pages/companies/companies-filters'; +import { companyAvailableSorts } from '~/pages/companies/companies-sorts'; + +const CompanyTableEffect = () => { + const { + setAvailableSorts, + setAvailableFilters, + setAvailableFields, + setViewType, + setViewObjectId, + } = useView(); + const { currentViewFields } = useViewInternalStates(); + + const [, setTableColumns] = useRecoilScopedState( + tableColumnsScopedState, + TableRecoilScopeContext, + ); + + const [, setAvailableTableColumns] = useRecoilScopedState( + availableTableColumnsScopedState, + TableRecoilScopeContext, + ); + + useEffect(() => { + setAvailableSorts?.(companyAvailableSorts); + setAvailableFilters?.(companyAvailableFilters); + setAvailableFields?.(companiesAvailableFieldDefinitions); + setViewObjectId?.('company'); + setViewType?.(ViewType.Table); + + setAvailableTableColumns(companiesAvailableFieldDefinitions); + }, [ + setAvailableFields, + setAvailableFilters, + setAvailableSorts, + setAvailableTableColumns, + setTableColumns, + setViewObjectId, + setViewType, + ]); + useEffect(() => { + if (currentViewFields) { + setTableColumns([...currentViewFields].sort((a, b) => a.index - b.index)); + } + }, [currentViewFields, setTableColumns]); + + return <>; +}; + +export default CompanyTableEffect; diff --git a/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx b/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx index a2105506a..3ab251a73 100644 --- a/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx +++ b/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx @@ -1,12 +1,11 @@ import { useEffect } from 'react'; +import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions'; import { useSetDataTableData } from '@/ui/data/data-table/hooks/useSetDataTableData'; import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { companiesAvailableColumnDefinitions } from '../../constants/companiesAvailableColumnDefinitions'; - import { mockedCompaniesData } from './companies-mock-data'; export const CompanyTableMockDataEffect = () => { @@ -19,7 +18,7 @@ export const CompanyTableMockDataEffect = () => { useEffect(() => { setDataTableData(mockedCompaniesData, [], []); - setTableColumns(companiesAvailableColumnDefinitions); + setTableColumns(companiesAvailableFieldDefinitions); }, [setDataTableData, setTableColumns]); return <>; diff --git a/front/src/modules/companies/table/components/CompanyTableMockMode.tsx b/front/src/modules/companies/table/components/CompanyTableMockMode.tsx index 8267a1ee1..aa09677aa 100644 --- a/front/src/modules/companies/table/components/CompanyTableMockMode.tsx +++ b/front/src/modules/companies/table/components/CompanyTableMockMode.tsx @@ -1,22 +1,15 @@ import { DataTable } from '@/ui/data/data-table/components/DataTable'; -import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; +import { ViewScope } from '@/views/scopes/ViewScope'; import { useUpdateOneCompanyMutation } from '~/generated/graphql'; import { CompanyTableMockDataEffect } from './CompanyTableMockDataEffect'; export const CompanyTableMockMode = () => { return ( - <> + - - - - + + + ); }; diff --git a/front/src/modules/metadata/components/ObjectDataTableEffect.tsx b/front/src/modules/metadata/components/ObjectDataTableEffect.tsx index ebe287084..13fdaddf8 100644 --- a/front/src/modules/metadata/components/ObjectDataTableEffect.tsx +++ b/front/src/modules/metadata/components/ObjectDataTableEffect.tsx @@ -3,12 +3,8 @@ import { useSearchParams } from 'react-router-dom'; import { useRecoilCallback } from 'recoil'; import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; -import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState'; -import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState'; -import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState'; import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; +import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState'; import { useFindManyObjects } from '../hooks/useFindManyObjects'; import { useSetObjectDataTableData } from '../hooks/useSetDataTableData'; @@ -39,22 +35,13 @@ export const ObjectDataTableEffect = ({ ({ set, snapshot }) => async (viewId: string) => { const currentView = await snapshot.getPromise( - currentViewIdScopedState(tableRecoilScopeId), + currentViewIdScopedState({ scopeId: tableRecoilScopeId }), ); if (currentView === viewId) { return; } - const savedFilters = await snapshot.getPromise( - savedFiltersFamilyState(viewId), - ); - const savedSorts = await snapshot.getPromise( - savedSortsFamilyState(viewId), - ); - - set(filtersScopedState(tableRecoilScopeId), savedFilters); - set(sortsScopedState(tableRecoilScopeId), savedSorts); - set(currentViewIdScopedState(tableRecoilScopeId), viewId); + set(currentViewIdScopedState({ scopeId: tableRecoilScopeId }), viewId); }, [tableRecoilScopeId], ); diff --git a/front/src/modules/metadata/components/ObjectTable.tsx b/front/src/modules/metadata/components/ObjectTable.tsx index e597a02a7..e70994e5c 100644 --- a/front/src/modules/metadata/components/ObjectTable.tsx +++ b/front/src/modules/metadata/components/ObjectTable.tsx @@ -1,9 +1,6 @@ import { DataTable } from '@/ui/data/data-table/components/DataTable'; import { TableContext } from '@/ui/data/data-table/contexts/TableContext'; -import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; -import { useMetadataTableViews } from '../hooks/useMetadataTableViews'; import { useUpdateOneObject } from '../hooks/useUpdateOneObject'; import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier'; @@ -12,9 +9,6 @@ import { ObjectDataTableEffect } from './ObjectDataTableEffect'; export type ObjectTableProps = MetadataObjectIdentifier; export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => { - const { createView, deleteView, submitCurrentView, updateView } = - useMetadataTableViews(); - const { updateOneObject } = useUpdateOneObject({ objectNamePlural, }); @@ -44,18 +38,8 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => { }} > - - - + + ); }; diff --git a/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts b/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts index bb1512525..127877327 100644 --- a/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts +++ b/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts @@ -6,7 +6,7 @@ import { FieldType } from '@/ui/data/field/types/FieldType'; import { IconBrandLinkedin } from '@/ui/display/icon'; import { GET_VIEW_FIELDS } from '@/views/graphql/queries/getViewFields'; import { GET_VIEWS } from '@/views/graphql/queries/getViews'; -import { toViewFieldInput } from '@/views/hooks/useTableViewFields'; +import { toViewFieldInput } from '@/views/hooks/internal/useViewFields'; import { useCreateViewFieldsMutation, useCreateViewMutation, diff --git a/front/src/modules/metadata/hooks/useMetadataTableViews.ts b/front/src/modules/metadata/hooks/useMetadataTableViews.ts deleted file mode 100644 index fef774933..000000000 --- a/front/src/modules/metadata/hooks/useMetadataTableViews.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { useSearchParams } from 'react-router-dom'; - -import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; -import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useTableViewFields } from '@/views/hooks/useTableViewFields'; -import { useViewFilters } from '@/views/hooks/useViewFilters'; -import { useViews } from '@/views/hooks/useViews'; -import { useViewSorts } from '@/views/hooks/useViewSorts'; -import { ViewType } from '~/generated/graphql'; - -import { useMetadataObjectInContext } from './useMetadataObjectInContext'; - -export const useMetadataTableViews = () => { - const { objectNamePlural, columnDefinitions } = useMetadataObjectInContext(); - - const tableColumns = useRecoilScopedValue( - tableColumnsScopedState, - TableRecoilScopeContext, - ); - const filters = useRecoilScopedValue( - filtersScopedState, - TableRecoilScopeContext, - ); - const sorts = useRecoilScopedValue(sortsScopedState, TableRecoilScopeContext); - - const [_, setSearchParams] = useSearchParams(); - - const handleViewCreate = async (viewId: string) => { - await createViewFields(tableColumns, viewId); - await createViewFilters(filters, viewId); - await createViewSorts(sorts, viewId); - setSearchParams({ view: viewId }); - }; - - const objectId = objectNamePlural; - - const { createView, deleteView, isFetchingViews, updateView } = useViews({ - objectId, - onViewCreate: handleViewCreate, - type: ViewType.Table, - RecoilScopeContext: TableRecoilScopeContext, - }); - - const { createViewFields, persistColumns } = useTableViewFields({ - objectId, - columnDefinitions, - skipFetch: isFetchingViews, - }); - - const createDefaultViewFields = async () => { - await createViewFields(tableColumns); - }; - - const { createViewFilters, persistFilters } = useViewFilters({ - RecoilScopeContext: TableRecoilScopeContext, - skipFetch: isFetchingViews, - }); - - const { createViewSorts, persistSorts } = useViewSorts({ - RecoilScopeContext: TableRecoilScopeContext, - skipFetch: isFetchingViews, - }); - - const submitCurrentView = async () => { - await persistFilters(); - await persistSorts(); - }; - - return { - createView, - deleteView, - persistColumns, - submitCurrentView, - updateView, - createDefaultViewFields, - isFetchingViews, - }; -}; diff --git a/front/src/modules/metadata/hooks/useSetDataTableData.ts b/front/src/modules/metadata/hooks/useSetDataTableData.ts index e983f5afc..0aae7fe38 100644 --- a/front/src/modules/metadata/hooks/useSetDataTableData.ts +++ b/front/src/modules/metadata/hooks/useSetDataTableData.ts @@ -6,10 +6,8 @@ import { numberOfTableRowsState } from '@/ui/data/data-table/states/numberOfTabl import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState'; import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState'; -import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState'; -import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState'; -import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState'; import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; +import { availableSortsScopedState } from '@/views/states/availableSortsScopedState'; export const useSetObjectDataTableData = () => { const resetTableRowSelection = useResetTableRowSelection(); @@ -43,11 +41,7 @@ export const useSetObjectDataTableData = () => { set(numberOfTableRowsState, entityIds.length); - set(entityCountInCurrentViewState, entityIds.length); - - set(availableFiltersScopedState(tableContextScopeId), []); - - set(availableSortsScopedState(tableContextScopeId), []); + set(availableSortsScopedState({ scopeId: tableContextScopeId }), []); set(isFetchingDataTableDataState, false); }, diff --git a/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx b/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx index 4c9aebf43..82175496a 100644 --- a/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx +++ b/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx @@ -1,23 +1,10 @@ import { useFilteredSearchPeopleQuery } from '@/people/hooks/useFilteredSearchPeopleQuery'; -import { FilterDropdownEntitySearchSelect } from '@/ui/data/view-bar/components/FilterDropdownEntitySearchSelect'; -import { useViewBarContext } from '@/ui/data/view-bar/hooks/useViewBarContext'; -import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState'; -import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; +import { FilterDropdownEntitySearchSelect } from '@/ui/data/filter/components/FilterDropdownEntitySearchSelect'; +import { useFilter } from '@/ui/data/filter/hooks/useFilter'; export const FilterDropdownPeopleSearchSelect = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const filterDropdownSearchInput = useRecoilScopedValue( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - - const [filterDropdownSelectedEntityId] = useRecoilScopedState( - filterDropdownSelectedEntityIdScopedState, - ViewBarRecoilScopeContext, - ); + const { filterDropdownSearchInput, filterDropdownSelectedEntityId } = + useFilter(); const peopleForSelect = useFilteredSearchPeopleQuery({ searchFilter: filterDropdownSearchInput, diff --git a/front/src/modules/people/hooks/useSetPeopleDataTable.ts b/front/src/modules/people/hooks/useSetPeopleDataTable.ts index 048534a51..365d9d1a3 100644 --- a/front/src/modules/people/hooks/useSetPeopleDataTable.ts +++ b/front/src/modules/people/hooks/useSetPeopleDataTable.ts @@ -4,13 +4,9 @@ import { useRecoilCallback } from 'recoil'; import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection'; import { isFetchingDataTableDataState } from '@/ui/data/data-table/states/isFetchingDataTableDataState'; import { numberOfTableRowsState } from '@/ui/data/data-table/states/numberOfTableRowsState'; -import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState'; -import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState'; import { currentPageLocationState } from '@/ui/utilities/loading-state/states/currentPageLocationState'; -import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; import { GetPeopleQuery } from '~/generated/graphql'; -import { peopleFilters } from '~/pages/people/people-filters'; import { peopleCityFamilyState } from '../states/peopleCityFamilyState'; import { peopleCompanyFamilyState } from '../states/peopleCompanyFamilyState'; @@ -24,8 +20,6 @@ import { peoplePhoneFamilyState } from '../states/peoplePhoneFamilyState'; export const useSetPeopleDataTable = () => { const resetTableRowSelection = useResetTableRowSelection(); - const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext); - const currentLocation = useLocation().pathname; return useRecoilCallback( @@ -126,12 +120,10 @@ export const useSetPeopleDataTable = () => { set(numberOfTableRowsState, peopleIds.length); - set(availableFiltersScopedState(tableContextScopeId), peopleFilters); - set(currentPageLocationState, currentLocation); set(isFetchingDataTableDataState, false); }, - [currentLocation, resetTableRowSelection, tableContextScopeId], + [currentLocation, resetTableRowSelection], ); }; diff --git a/front/src/modules/people/table/components/PeopleTable.tsx b/front/src/modules/people/table/components/PeopleTable.tsx index c056e5e98..3c0dcfbaf 100644 --- a/front/src/modules/people/table/components/PeopleTable.tsx +++ b/front/src/modules/people/table/components/PeopleTable.tsx @@ -1,15 +1,12 @@ -import { peopleAvailableColumnDefinitions } from '@/people/constants/peopleAvailableColumnDefinitions'; import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition'; import { usePersonTableContextMenuEntries } from '@/people/hooks/usePeopleTableContextMenuEntries'; import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries'; -import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport'; import { DataTable } from '@/ui/data/data-table/components/DataTable'; import { DataTableEffect } from '@/ui/data/data-table/components/DataTableEffect'; import { TableContext } from '@/ui/data/data-table/contexts/TableContext'; import { useUpsertDataTableItem } from '@/ui/data/data-table/hooks/useUpsertDataTableItem'; -import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; -import { useTableViews } from '@/views/hooks/useTableViews'; +import { SortScope } from '@/ui/data/sort/scopes/SortScope'; +import { ViewScope } from '@/views/scopes/ViewScope'; import { UpdateOnePersonMutationVariables, useGetPeopleQuery, @@ -21,68 +18,54 @@ import { peopleAvailableSorts } from '~/pages/people/people-sorts'; export const PeopleTable = () => { const [updateEntityMutation] = useUpdateOnePersonMutation(); const upsertDataTableItem = useUpsertDataTableItem(); - const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport(); - const { - createView, - deleteView, - persistColumns, - submitCurrentView, - updateView, - } = useTableViews({ - objectId: 'person', - columnDefinitions: peopleAvailableColumnDefinitions, - }); + const tableViewScopeId = 'people-table'; const { setContextMenuEntries } = usePersonTableContextMenuEntries(); const { setActionBarEntries } = usePersonTableActionBarEntries(); - const handleImport = () => { - openPersonSpreadsheetImport(); - }; - return ( - - - - - updateEntityMutation({ + + + { + // eslint-disable-next-line no-console + console.log('persist columns'); + }, + }} + > + + + { - if (!data.updateOnePerson) { - return; - } - upsertDataTableItem(data.updateOnePerson); - }, - }) - } - /> - - + }: { + variables: UpdateOnePersonMutationVariables; + }) => + updateEntityMutation({ + variables, + onCompleted: (data) => { + if (!data.updateOnePerson) { + return; + } + upsertDataTableItem(data.updateOnePerson); + }, + }) + } + /> + + + ); }; diff --git a/front/src/modules/ui/data/data-table/components/DataTable.tsx b/front/src/modules/ui/data/data-table/components/DataTable.tsx index fc8361a35..94ec5a9d8 100644 --- a/front/src/modules/ui/data/data-table/components/DataTable.tsx +++ b/front/src/modules/ui/data/data-table/components/DataTable.tsx @@ -14,7 +14,6 @@ import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus'; import { useMapKeyboardToSoftFocus } from '../hooks/useMapKeyboardToSoftFocus'; import { useResetTableRowSelection } from '../hooks/useResetTableRowSelection'; import { useSetRowSelectedState } from '../hooks/useSetRowSelectedState'; -import { TableHeader } from '../table-header/components/TableHeader'; import { TableHotkeyScope } from '../types/TableHotkeyScope'; import { DataTableBody } from './DataTableBody'; @@ -123,7 +122,6 @@ export const DataTable = ({ updateEntityMutation }: DataTableProps) => { -
diff --git a/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx b/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx index 11caa87a5..39fb2aa0f 100644 --- a/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx +++ b/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx @@ -1,27 +1,21 @@ import { useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import defaults from 'lodash/defaults'; -import { useRecoilCallback } from 'recoil'; import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; import { OptimisticEffectDefinition } from '@/apollo/optimistic-effect/types/OptimisticEffectDefinition'; -import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; -import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState'; -import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState'; -import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState'; -import { FilterDefinition } from '@/ui/data/view-bar/types/FilterDefinition'; -import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition'; +import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; +import { useView } from '@/views/hooks/useView'; +import { useViewInternalStates } from '@/views/hooks/useViewInternalStates'; import { SortOrder, useGetCompaniesQuery, useGetPeopleQuery, } from '~/generated/graphql'; -import { filtersWhereScopedSelector } from '../../view-bar/states/selectors/filtersWhereScopedSelector'; -import { sortsOrderByScopedSelector } from '../../view-bar/states/selectors/sortsOrderByScopedSelector'; +import { filtersWhereScopedSelector } from '../../filter/states/selectors/filtersWhereScopedSelector'; +import { SortDefinition } from '../../sort/types/SortDefinition'; import { useSetDataTableData } from '../hooks/useSetDataTableData'; import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext'; @@ -46,12 +40,10 @@ export const DataTableEffect = ({ }) => { const setDataTableData = useSetDataTableData(); const { registerOptimisticEffect } = useOptimisticEffect(); + const { setCurrentViewId } = useView(); + const { currentViewSortsOrderBy } = useViewInternalStates(); - let sortsOrderBy = useRecoilScopedValue( - sortsOrderByScopedSelector, - TableRecoilScopeContext, - ); - sortsOrderBy = defaults(sortsOrderBy, [ + const sortsOrderBy = defaults(currentViewSortsOrderBy, [ { createdAt: SortOrder.Desc, }, @@ -76,43 +68,19 @@ export const DataTableEffect = ({ }); const [searchParams] = useSearchParams(); - const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext); - const handleViewSelect = useRecoilCallback( - ({ set, snapshot }) => - async (viewId: string) => { - const currentView = await snapshot.getPromise( - currentViewIdScopedState(tableRecoilScopeId), - ); - if (currentView === viewId) { - return; - } - - const savedFilters = await snapshot.getPromise( - savedFiltersFamilyState(viewId), - ); - const savedSorts = await snapshot.getPromise( - savedSortsFamilyState(viewId), - ); - - set(filtersScopedState(tableRecoilScopeId), savedFilters); - set(sortsScopedState(tableRecoilScopeId), savedSorts); - set(currentViewIdScopedState(tableRecoilScopeId), viewId); - }, - [tableRecoilScopeId], - ); useEffect(() => { const viewId = searchParams.get('view'); if (viewId) { - handleViewSelect(viewId); + //setCurrentViewId(viewId); } setActionBarEntries?.(); setContextMenuEntries?.(); }, [ - handleViewSelect, searchParams, setActionBarEntries, setContextMenuEntries, + setCurrentViewId, ]); return <>; diff --git a/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx b/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx index 304e69162..e5e9fe829 100644 --- a/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx +++ b/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx @@ -166,33 +166,35 @@ export const DataTableHeader = () => { > - {visibleTableColumns.map((column, index) => ( - - - columnA.index - columnB.index) + .map((column, index) => ( + + + + + { + setResizedFieldKey(column.key); + }} /> - - { - setResizedFieldKey(column.key); - }} - /> - - ))} + + ))} {hiddenTableColumns.length > 0 && ( diff --git a/front/src/modules/ui/data/data-table/components/DataTableRow.tsx b/front/src/modules/ui/data/data-table/components/DataTableRow.tsx index 0515d6bc0..5600163d2 100644 --- a/front/src/modules/ui/data/data-table/components/DataTableRow.tsx +++ b/front/src/modules/ui/data/data-table/components/DataTableRow.tsx @@ -38,13 +38,15 @@ export const DataTableRow = forwardRef( - {visibleTableColumns.map((column, columnIndex) => { - return ( - - - - ); - })} + {[...visibleTableColumns] + .sort((columnA, columnB) => columnA.index - columnB.index) + .map((column, columnIndex) => { + return ( + + + + ); + })} ); diff --git a/front/src/modules/views/hooks/useMoveViewColumns.ts b/front/src/modules/ui/data/data-table/hooks/useMoveViewColumns.ts similarity index 100% rename from front/src/modules/views/hooks/useMoveViewColumns.ts rename to front/src/modules/ui/data/data-table/hooks/useMoveViewColumns.ts diff --git a/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts b/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts index aea4af97d..4ef19f7aa 100644 --- a/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts +++ b/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts @@ -1,13 +1,12 @@ import { useRecoilCallback } from 'recoil'; import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState'; -import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState'; -import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState'; -import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState'; -import { FilterDefinition } from '@/ui/data/view-bar/types/FilterDefinition'; -import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition'; +import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition'; import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; +import { useView } from '@/views/hooks/useView'; +import { availableSortsScopedState } from '@/views/states/availableSortsScopedState'; +import { SortDefinition } from '../../sort/types/SortDefinition'; import { isFetchingDataTableDataState } from '../states/isFetchingDataTableDataState'; import { numberOfTableRowsState } from '../states/numberOfTableRowsState'; import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext'; @@ -17,6 +16,7 @@ import { useResetTableRowSelection } from './useResetTableRowSelection'; export const useSetDataTableData = () => { const resetTableRowSelection = useResetTableRowSelection(); + const { setEntityCountInCurrentView } = useView(); const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext); @@ -51,20 +51,15 @@ export const useSetDataTableData = () => { set(numberOfTableRowsState, entityIds.length); - set(entityCountInCurrentViewState, entityIds.length); + setEntityCountInCurrentView(entityIds.length); set( - availableFiltersScopedState(tableContextScopeId), - filterDefinitionArray, - ); - - set( - availableSortsScopedState(tableContextScopeId), + availableSortsScopedState({ scopeId: tableContextScopeId }), sortDefinitionArray, ); set(isFetchingDataTableDataState, false); }, - [resetTableRowSelection, tableContextScopeId], + [resetTableRowSelection, setEntityCountInCurrentView, tableContextScopeId], ); }; diff --git a/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts b/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts index 2aa248217..f37d8e500 100644 --- a/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts +++ b/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts @@ -1,12 +1,11 @@ import { useCallback, useContext } from 'react'; import { useSetRecoilState } from 'recoil'; +import { useMoveViewColumns } from '@/ui/data/data-table/hooks/useMoveViewColumns'; import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata'; -import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState'; -import { ViewFieldForVisibility } from '@/ui/data/view-bar/types/ViewFieldForVisibility'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns'; +import { useView } from '@/views/hooks/useView'; +import { ViewFieldForVisibility } from '@/views/types/ViewFieldForVisibility'; import { TableContext } from '../contexts/TableContext'; import { availableTableColumnsScopedState } from '../states/availableTableColumnsScopedState'; @@ -23,10 +22,8 @@ export const useTableColumns = () => { TableRecoilScopeContext, ); - const currentViewId = useRecoilScopedValue( - currentViewIdScopedState, - TableRecoilScopeContext, - ); + const { currentViewId } = useView(); + const setSavedTableColumns = useSetRecoilState( savedTableColumnsFamilyState(currentViewId), ); @@ -91,7 +88,10 @@ export const useTableColumns = () => { ); const handleMoveTableColumn = useCallback( - (direction: 'left' | 'right', column: ColumnDefinition) => { + async ( + direction: 'left' | 'right', + column: ColumnDefinition, + ) => { const currentColumnArrayIndex = tableColumns.findIndex( (tableColumn) => tableColumn.key === column.key, ); @@ -101,9 +101,9 @@ export const useTableColumns = () => { tableColumns, ); - setTableColumns(columns); + await handleColumnsChange(columns); }, - [tableColumns, setTableColumns, handleColumnMove], + [tableColumns, handleColumnMove, handleColumnsChange], ); return { diff --git a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx index b99cbe534..e77b1876b 100644 --- a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx +++ b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx @@ -1,9 +1,7 @@ -import { useResetRecoilState } from 'recoil'; - -import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; +import { useView } from '@/views/hooks/useView'; import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId'; @@ -17,7 +15,7 @@ type TableOptionsDropdownProps = { export const TableOptionsDropdown = ({ customHotkeyScope, }: TableOptionsDropdownProps) => { - const resetViewEditMode = useResetRecoilState(viewEditModeState); + const { setViewEditMode } = useView(); return ( @@ -26,7 +24,7 @@ export const TableOptionsDropdown = ({ dropdownHotkeyScope={customHotkeyScope} dropdownOffset={{ y: 8 }} dropdownComponents={} - onClickOutside={resetViewEditMode} + onClickOutside={() => setViewEditMode('none')} /> ); diff --git a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx index e27495189..c5c54d13d 100644 --- a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx +++ b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx @@ -1,15 +1,8 @@ -import { useCallback, useContext, useRef, useState } from 'react'; +import { useCallback, useRef, useState } from 'react'; import { OnDragEndResponder } from '@hello-pangea/dnd'; -import { useRecoilCallback, useRecoilValue, useResetRecoilState } from 'recoil'; import { Key } from 'ts-key-enum'; -import { ViewFieldsVisibilityDropdownSection } from '@/ui/data/view-bar/components/ViewFieldsVisibilityDropdownSection'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; -import { useUpsertView } from '@/ui/data/view-bar/hooks/useUpsertView'; -import { currentViewScopedSelector } from '@/ui/data/view-bar/states/selectors/currentViewScopedSelector'; -import { viewsByIdScopedSelector } from '@/ui/data/view-bar/states/selectors/viewsByIdScopedSelector'; -import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState'; -import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon'; +import { IconChevronLeft, IconTag } from '@/ui/display/icon'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -18,22 +11,22 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; +import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection'; +import { useView } from '@/views/hooks/useView'; +import { useViewInternalStates } from '@/views/hooks/useViewInternalStates'; import { useTableColumns } from '../../hooks/useTableColumns'; import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext'; -import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState'; import { hiddenTableColumnsScopedSelector } from '../../states/selectors/hiddenTableColumnsScopedSelector'; import { visibleTableColumnsScopedSelector } from '../../states/selectors/visibleTableColumnsScopedSelector'; -import { tableColumnsScopedState } from '../../states/tableColumnsScopedState'; import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope'; type TableOptionsMenu = 'fields'; export const TableOptionsDropdownContent = () => { - const scopeId = useRecoilScopeId(TableRecoilScopeContext); + const { setViewEditMode, handleViewNameSubmit } = useView(); + const { viewEditMode, currentView } = useViewInternalStates(); - const { onImport } = useContext(ViewBarContext); const { closeDropdown } = useDropdown(); const [currentMenu, setCurrentMenu] = useState( @@ -42,12 +35,6 @@ export const TableOptionsDropdownContent = () => { const viewEditInputRef = useRef(null); - const currentView = useRecoilScopedValue( - currentViewScopedSelector, - TableRecoilScopeContext, - ); - const viewEditMode = useRecoilValue(viewEditModeState); - const resetViewEditMode = useResetRecoilState(viewEditModeState); const visibleTableColumns = useRecoilScopedValue( visibleTableColumnsScopedSelector, TableRecoilScopeContext, @@ -56,35 +43,13 @@ export const TableOptionsDropdownContent = () => { hiddenTableColumnsScopedSelector, TableRecoilScopeContext, ); - const viewsById = useRecoilScopedValue( - viewsByIdScopedSelector, - TableRecoilScopeContext, - ); const { handleColumnVisibilityChange, handleColumnReorder } = useTableColumns(); - const { upsertView } = useUpsertView(); - - const handleViewNameSubmit = useRecoilCallback( - ({ set, snapshot }) => - async () => { - const tableColumns = await snapshot.getPromise( - tableColumnsScopedState(scopeId), - ); - const isCreateMode = viewEditMode.mode === 'create'; - const name = viewEditInputRef.current?.value; - const view = await upsertView(name); - - if (view && isCreateMode) { - set(savedTableColumnsFamilyState(view.id), tableColumns); - } - }, - [scopeId, upsertView, viewEditMode.mode], - ); - const handleSelectMenu = (option: TableOptionsMenu) => { - handleViewNameSubmit(); + const name = viewEditInputRef.current?.value; + handleViewNameSubmit(name); setCurrentMenu(option); }; @@ -108,7 +73,6 @@ export const TableOptionsDropdownContent = () => { useScopedHotkeys( Key.Escape, () => { - resetViewEditMode(); closeDropdown(); }, TableOptionsHotkeyScope.Dropdown, @@ -117,9 +81,10 @@ export const TableOptionsDropdownContent = () => { useScopedHotkeys( Key.Enter, () => { - handleViewNameSubmit(); + const name = viewEditInputRef.current?.value; + handleViewNameSubmit(name); resetMenu(); - resetViewEditMode(); + setViewEditMode('none'); closeDropdown(); }, TableOptionsHotkeyScope.Dropdown, @@ -130,16 +95,21 @@ export const TableOptionsDropdownContent = () => { {!currentMenu && ( <> @@ -149,13 +119,13 @@ export const TableOptionsDropdownContent = () => { LeftIcon={IconTag} text="Fields" /> - {onImport && ( + {/*onImport && ( - )} + )*/} )} diff --git a/front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx b/front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx deleted file mode 100644 index 0b81a898c..000000000 --- a/front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { userEvent, within } from '@storybook/testing-library'; - -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; -import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; - -import { TableRecoilScopeContext } from '../../../states/recoil-scope-contexts/TableRecoilScopeContext'; -import { TableOptionsDropdown } from '../TableOptionsDropdown'; - -const meta: Meta = { - title: 'UI/Data/DataTable/Options/TableOptionsDropdown', - component: TableOptionsDropdown, - decorators: [ - (Story) => ( - - - - - - ), - ComponentDecorator, - ], -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - customHotkeyScope: { scope: 'options' }, - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - const dropdownButton = canvas.getByText('Options'); - - await userEvent.click(dropdownButton); - }, -}; diff --git a/front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx b/front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx deleted file mode 100644 index 37c7b4c27..000000000 --- a/front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useContext } from 'react'; -import { useSearchParams } from 'react-router-dom'; -import { useRecoilCallback } from 'recoil'; - -import { ViewBar } from '@/ui/data/view-bar/components/ViewBar'; -import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext'; -import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; - -import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId'; -import { TableOptionsDropdown } from '../../options/components/TableOptionsDropdown'; -import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext'; -import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState'; -import { tableColumnsScopedState } from '../../states/tableColumnsScopedState'; -import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope'; - -export const TableHeader = () => { - const { onCurrentViewSubmit, ...viewBarContextProps } = - useContext(ViewBarContext); - const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext); - const [_, setSearchParams] = useSearchParams(); - - const handleViewSelect = useRecoilCallback( - ({ set, snapshot }) => - async (viewId: string) => { - const savedTableColumns = await snapshot.getPromise( - savedTableColumnsFamilyState(viewId), - ); - set(tableColumnsScopedState(tableRecoilScopeId), savedTableColumns); - setSearchParams({ view: viewId }); - }, - [tableRecoilScopeId, setSearchParams], - ); - - return ( - - - } - optionsDropdownScopeId={TableOptionsDropdownId} - /> - - ); -}; diff --git a/front/src/modules/ui/data/view-bar/components/AddFilterFromDetailsButton.tsx b/front/src/modules/ui/data/filter/components/AddFilterFromDetailsButton.tsx similarity index 100% rename from front/src/modules/ui/data/view-bar/components/AddFilterFromDetailsButton.tsx rename to front/src/modules/ui/data/filter/components/AddFilterFromDetailsButton.tsx diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownButton.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownButton.tsx similarity index 63% rename from front/src/modules/ui/data/view-bar/components/FilterDropdownButton.tsx rename to front/src/modules/ui/data/filter/components/FilterDropdownButton.tsx index 2afbc7ead..f4ae61453 100644 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownButton.tsx +++ b/front/src/modules/ui/data/filter/components/FilterDropdownButton.tsx @@ -1,8 +1,6 @@ import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { availableFiltersScopedState } from '../states/availableFiltersScopedState'; +import { useFilter } from '../hooks/useFilter'; import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton'; import { SingleEntityFilterDropdownButton } from './SingleEntityFilterDropdownButton'; @@ -14,12 +12,7 @@ type FilterDropdownButtonProps = { export const FilterDropdownButton = ({ hotkeyScope, }: FilterDropdownButtonProps) => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [availableFilters] = useRecoilScopedState( - availableFiltersScopedState, - ViewBarRecoilScopeContext, - ); + const { availableFilters } = useFilter(); const hasOnlyOneEntityFilter = availableFilters.length === 1 && availableFilters[0].type === 'entity'; diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx new file mode 100644 index 000000000..7ec5056d1 --- /dev/null +++ b/front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx @@ -0,0 +1,36 @@ +import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker'; +import { useUpsertFilter } from '@/views/hooks/useUpsertFilter'; + +import { useFilter } from '../hooks/useFilter'; + +export const FilterDropdownDateSearchInput = () => { + const { + filterDefinitionUsedInDropdown, + selectedOperandInDropdown, + setIsFilterDropdownUnfolded, + } = useFilter(); + + const upsertFilter = useUpsertFilter(); + + const handleChange = (date: Date) => { + if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; + + upsertFilter({ + key: filterDefinitionUsedInDropdown.key, + type: filterDefinitionUsedInDropdown.type, + value: date.toISOString(), + operand: selectedOperandInDropdown, + displayValue: date.toLocaleDateString(), + }); + + setIsFilterDropdownUnfolded(false); + }; + + return ( + + ); +}; diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx new file mode 100644 index 000000000..849e4f5f4 --- /dev/null +++ b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx @@ -0,0 +1,29 @@ +import { ChangeEvent } from 'react'; + +import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; + +import { useFilter } from '../hooks/useFilter'; + +export const FilterDropdownEntitySearchInput = () => { + const { + filterDefinitionUsedInDropdown, + selectedOperandInDropdown, + filterDropdownSearchInput, + setFilterDropdownSearchInput, + } = useFilter(); + + return ( + filterDefinitionUsedInDropdown && + selectedOperandInDropdown && ( + ) => { + setFilterDropdownSearchInput(event.target.value); + }} + /> + ) + ); +}; diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchSelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchSelect.tsx similarity index 70% rename from front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchSelect.tsx rename to front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchSelect.tsx index e044464d2..dd668512f 100644 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchSelect.tsx +++ b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchSelect.tsx @@ -1,45 +1,30 @@ import { useEffect, useState } from 'react'; -import { useFilterCurrentlyEdited } from '@/ui/data/view-bar/hooks/useFilterCurrentlyEdited'; -import { useRemoveFilter } from '@/ui/data/view-bar/hooks/useRemoveFilter'; -import { useUpsertFilter } from '@/ui/data/view-bar/hooks/useUpsertFilter'; -import { filterDefinitionUsedInDropdownScopedState } from '@/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState'; -import { selectedOperandInDropdownScopedState } from '@/ui/data/view-bar/states/selectedOperandInDropdownScopedState'; +import { useFilterCurrentlyEdited } from '@/ui/data/filter/hooks/useFilterCurrentlyEdited'; import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect'; import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; +import { useRemoveFilter } from '@/views/hooks/useRemoveFilter'; +import { useUpsertFilter } from '@/views/hooks/useUpsertFilter'; import { ViewFilterOperand } from '~/generated/graphql'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; +import { useFilter } from '../hooks/useFilter'; export const FilterDropdownEntitySearchSelect = ({ entitiesForSelect, }: { entitiesForSelect: EntitiesForMultipleEntitySelect; }) => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); + const { + filterDropdownSelectedEntityId, + setFilterDropdownSelectedEntityId, + filterDefinitionUsedInDropdown, + selectedOperandInDropdown, + filterDropdownSearchInput, + } = useFilter(); const [isAllEntitySelected, setIsAllEntitySelected] = useState(false); - const [filterDropdownSelectedEntityId, setFilterDropdownSelectedEntityId] = - useRecoilScopedState( - filterDropdownSelectedEntityIdScopedState, - ViewBarRecoilScopeContext, - ); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - const upsertFilter = useUpsertFilter(); const removeFilter = useRemoveFilter(); @@ -80,11 +65,6 @@ export const FilterDropdownEntitySearchSelect = ({ } }; - const [filterDropdownSearchInput] = useRecoilScopedState( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - const isAllEntitySelectShown = !!filterDefinitionUsedInDropdown?.selectAllLabel && !!filterDefinitionUsedInDropdown?.SelectAllIcon && diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx new file mode 100644 index 000000000..5653685ef --- /dev/null +++ b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx @@ -0,0 +1,21 @@ +import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; +import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; + +import { useFilter } from '../hooks/useFilter'; + +export const FilterDropdownEntitySelect = () => { + const { filterDefinitionUsedInDropdown } = useFilter(); + + if (filterDefinitionUsedInDropdown?.type !== 'entity') { + return null; + } + + return ( + <> + + + {filterDefinitionUsedInDropdown.entitySelectComponent} + + + ); +}; diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownFilterSelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownFilterSelect.tsx similarity index 50% rename from front/src/modules/ui/data/view-bar/components/FilterDropdownFilterSelect.tsx rename to front/src/modules/ui/data/filter/components/FilterDropdownFilterSelect.tsx index 105dd38ce..556282495 100644 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownFilterSelect.tsx +++ b/front/src/modules/ui/data/filter/components/FilterDropdownFilterSelect.tsx @@ -2,38 +2,17 @@ import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/Rela import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { availableFiltersScopedState } from '../states/availableFiltersScopedState'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; +import { useFilter } from '../hooks/useFilter'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; export const FilterDropdownFilterSelect = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setSelectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setFilterDropdownSearchInput] = useRecoilScopedState( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - - const availableFilters = useRecoilScopedValue( - availableFiltersScopedState, - ViewBarRecoilScopeContext, - ); + const { + setFilterDefinitionUsedInDropdown, + setSelectedOperandInDropdown, + setFilterDropdownSearchInput, + availableFilters, + } = useFilter(); const setHotkeyScope = useSetHotkeyScope(); diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownNumberSearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownNumberSearchInput.tsx similarity index 54% rename from front/src/modules/ui/data/view-bar/components/FilterDropdownNumberSearchInput.tsx rename to front/src/modules/ui/data/filter/components/FilterDropdownNumberSearchInput.tsx index 11cb6593f..ea8fc8585 100644 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownNumberSearchInput.tsx +++ b/front/src/modules/ui/data/filter/components/FilterDropdownNumberSearchInput.tsx @@ -1,26 +1,14 @@ import { ChangeEvent } from 'react'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useRemoveFilter } from '../hooks/useRemoveFilter'; -import { useUpsertFilter } from '../hooks/useUpsertFilter'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; +import { useRemoveFilter } from '../../../../views/hooks/useRemoveFilter'; +import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter'; +import { useFilter } from '../hooks/useFilter'; export const FilterDropdownNumberSearchInput = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); + const { selectedOperandInDropdown, filterDefinitionUsedInDropdown } = + useFilter(); const upsertFilter = useUpsertFilter(); const removeFilter = useRemoveFilter(); diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx new file mode 100644 index 000000000..1aa96c3a5 --- /dev/null +++ b/front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx @@ -0,0 +1,27 @@ +import { IconChevronDown } from '@/ui/display/icon'; +import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; + +import { useFilter } from '../hooks/useFilter'; +import { getOperandLabel } from '../utils/getOperandLabel'; + +export const FilterDropdownOperandButton = () => { + const { + selectedOperandInDropdown, + setIsFilterDropdownOperandSelectUnfolded, + isFilterDropdownOperandSelectUnfolded, + } = useFilter(); + + if (isFilterDropdownOperandSelectUnfolded) { + return null; + } + + return ( + setIsFilterDropdownOperandSelectUnfolded(true)} + > + {getOperandLabel(selectedOperandInDropdown)} + + ); +}; diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandSelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownOperandSelect.tsx similarity index 62% rename from front/src/modules/ui/data/view-bar/components/FilterDropdownOperandSelect.tsx rename to front/src/modules/ui/data/filter/components/FilterDropdownOperandSelect.tsx index abd243504..5bfe4ef8b 100644 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandSelect.tsx +++ b/front/src/modules/ui/data/filter/components/FilterDropdownOperandSelect.tsx @@ -1,42 +1,25 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { ViewFilterOperand } from '~/generated/graphql'; +import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter'; +import { useFilter } from '../hooks/useFilter'; import { useFilterCurrentlyEdited } from '../hooks/useFilterCurrentlyEdited'; -import { useUpsertFilter } from '../hooks/useUpsertFilter'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; import { getOperandLabel } from '../utils/getOperandLabel'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; export const FilterDropdownOperandSelect = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setSelectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); + const { + filterDefinitionUsedInDropdown, + setSelectedOperandInDropdown, + isFilterDropdownOperandSelectUnfolded, + setIsFilterDropdownOperandSelectUnfolded, + } = useFilter(); const operandsForFilterType = getOperandsForFilterType( filterDefinitionUsedInDropdown?.type, ); - const [ - isFilterDropdownOperandSelectUnfolded, - setIsFilterDropdownOperandSelectUnfolded, - ] = useRecoilScopedState( - isFilterDropdownOperandSelectUnfoldedScopedState, - ViewBarRecoilScopeContext, - ); - const filterCurrentlyEdited = useFilterCurrentlyEdited(); const upsertFilter = useUpsertFilter(); diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownTextSearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownTextSearchInput.tsx similarity index 53% rename from front/src/modules/ui/data/view-bar/components/FilterDropdownTextSearchInput.tsx rename to front/src/modules/ui/data/filter/components/FilterDropdownTextSearchInput.tsx index fb1e0b0ef..b65cc5dc7 100644 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownTextSearchInput.tsx +++ b/front/src/modules/ui/data/filter/components/FilterDropdownTextSearchInput.tsx @@ -1,34 +1,19 @@ import { ChangeEvent } from 'react'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; +import { useRemoveFilter } from '../../../../views/hooks/useRemoveFilter'; +import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter'; +import { useFilter } from '../hooks/useFilter'; import { useFilterCurrentlyEdited } from '../hooks/useFilterCurrentlyEdited'; -import { useRemoveFilter } from '../hooks/useRemoveFilter'; -import { useUpsertFilter } from '../hooks/useUpsertFilter'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; export const FilterDropdownTextSearchInput = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [filterDropdownSearchInput, setFilterDropdownSearchInput] = - useRecoilScopedState( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); + const { + filterDefinitionUsedInDropdown, + selectedOperandInDropdown, + filterDropdownSearchInput, + setFilterDropdownSearchInput, + } = useFilter(); const upsertFilter = useUpsertFilter(); const removeFilter = useRemoveFilter(); diff --git a/front/src/modules/ui/data/view-bar/components/GenericEntityFilterChip.tsx b/front/src/modules/ui/data/filter/components/GenericEntityFilterChip.tsx similarity index 100% rename from front/src/modules/ui/data/view-bar/components/GenericEntityFilterChip.tsx rename to front/src/modules/ui/data/filter/components/GenericEntityFilterChip.tsx diff --git a/front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx new file mode 100644 index 000000000..e00545af2 --- /dev/null +++ b/front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx @@ -0,0 +1,39 @@ +import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; +import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; + +import { FilterDropdownId } from '../constants/FilterDropdownId'; +import { useFilter } from '../hooks/useFilter'; + +export const MultipleFiltersButton = () => { + const { + setFilterDefinitionUsedInDropdown, + setIsFilterDropdownOperandSelectUnfolded, + setFilterDropdownSearchInput, + setSelectedOperandInDropdown, + } = useFilter(); + + const { isDropdownOpen, toggleDropdown } = useDropdown({ + dropdownScopeId: FilterDropdownId, + }); + + const resetState = () => { + setIsFilterDropdownOperandSelectUnfolded(false); + setFilterDefinitionUsedInDropdown(null); + setSelectedOperandInDropdown(null); + setFilterDropdownSearchInput(''); + }; + + const handleClick = () => { + toggleDropdown(); + resetState(); + }; + + return ( + + Filter + + ); +}; diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownButton.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownButton.tsx similarity index 100% rename from front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownButton.tsx rename to front/src/modules/ui/data/filter/components/MultipleFiltersDropdownButton.tsx diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownContent.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownContent.tsx similarity index 67% rename from front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownContent.tsx rename to front/src/modules/ui/data/filter/components/MultipleFiltersDropdownContent.tsx index 0cd002eee..61ed8c50c 100644 --- a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownContent.tsx +++ b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownContent.tsx @@ -1,10 +1,6 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; +import { useFilter } from '../hooks/useFilter'; import { FilterDropdownDateSearchInput } from './FilterDropdownDateSearchInput'; import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput'; @@ -17,22 +13,11 @@ import { FilterDropdownTextSearchInput } from './FilterDropdownTextSearchInput'; import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect'; export const MultipleFiltersDropdownContent = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [isFilterDropdownOperandSelectUnfolded] = useRecoilScopedState( - isFilterDropdownOperandSelectUnfoldedScopedState, - ViewBarRecoilScopeContext, - ); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); + const { + isFilterDropdownOperandSelectUnfolded, + filterDefinitionUsedInDropdown, + selectedOperandInDropdown, + } = useFilter(); return ( <> diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx similarity index 100% rename from front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx rename to front/src/modules/ui/data/filter/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx diff --git a/front/src/modules/ui/data/view-bar/components/SingleEntityFilterDropdownButton.tsx b/front/src/modules/ui/data/filter/components/SingleEntityFilterDropdownButton.tsx similarity index 62% rename from front/src/modules/ui/data/view-bar/components/SingleEntityFilterDropdownButton.tsx rename to front/src/modules/ui/data/filter/components/SingleEntityFilterDropdownButton.tsx index efa7baaf1..2b24a0051 100644 --- a/front/src/modules/ui/data/view-bar/components/SingleEntityFilterDropdownButton.tsx +++ b/front/src/modules/ui/data/filter/components/SingleEntityFilterDropdownButton.tsx @@ -6,14 +6,9 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { ViewFilterOperand } from '~/generated/graphql'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { availableFiltersScopedState } from '../states/availableFiltersScopedState'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { filtersScopedState } from '../states/filtersScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; +import { useFilter } from '../hooks/useFilter'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput'; @@ -25,29 +20,15 @@ export const SingleEntityFilterDropdownButton = ({ }: { hotkeyScope: HotkeyScope; }) => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); + const { + availableFilters, + selectedFilters, + setFilterDefinitionUsedInDropdown, + setSelectedOperandInDropdown, + } = useFilter(); - const [availableFilters] = useRecoilScopedState( - availableFiltersScopedState, - ViewBarRecoilScopeContext, - ); const availableFilter = availableFilters[0]; - const [filters] = useRecoilScopedState( - filtersScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setSelectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - React.useEffect(() => { setFilterDefinitionUsedInDropdown(availableFilter); const defaultOperand = getOperandsForFilterType(availableFilter?.type)[0]; @@ -67,11 +48,11 @@ export const SingleEntityFilterDropdownButton = ({ dropdownOffset={{ x: 0, y: -28 }} clickableComponent={ - {filters[0] ? ( + {selectedFilters[0] ? ( { + const scopeId = useAvailableScopeIdOrThrow( + FilterScopeInternalContext, + props?.filterScopeId, + ); + const { + availableFilters, + setAvailableFilters, + filterDefinitionUsedInDropdown, + setFilterDefinitionUsedInDropdown, + filterDropdownSearchInput, + setFilterDropdownSearchInput, + filterDropdownSelectedEntityId, + setFilterDropdownSelectedEntityId, + isFilterDropdownOperandSelectUnfolded, + setIsFilterDropdownOperandSelectUnfolded, + isFilterDropdownUnfolded, + setIsFilterDropdownUnfolded, + selectedFilters, + setSelectedFilters, + selectedOperandInDropdown, + setSelectedOperandInDropdown, + } = useFilterStates(scopeId); + + return { + scopeId, + availableFilters, + setAvailableFilters, + filterDefinitionUsedInDropdown, + setFilterDefinitionUsedInDropdown, + filterDropdownSearchInput, + setFilterDropdownSearchInput, + filterDropdownSelectedEntityId, + setFilterDropdownSelectedEntityId, + isFilterDropdownOperandSelectUnfolded, + setIsFilterDropdownOperandSelectUnfolded, + isFilterDropdownUnfolded, + setIsFilterDropdownUnfolded, + selectedFilters, + setSelectedFilters, + selectedOperandInDropdown, + setSelectedOperandInDropdown, + }; +}; diff --git a/front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts b/front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts new file mode 100644 index 000000000..e0d4e4e5f --- /dev/null +++ b/front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts @@ -0,0 +1,13 @@ +import { useMemo } from 'react'; + +import { useFilter } from './useFilter'; + +export const useFilterCurrentlyEdited = () => { + const { selectedFilters, filterDefinitionUsedInDropdown } = useFilter(); + + return useMemo(() => { + return selectedFilters?.find( + (filter) => filter.key === filterDefinitionUsedInDropdown?.key, + ); + }, [filterDefinitionUsedInDropdown?.key, selectedFilters]); +}; diff --git a/front/src/modules/ui/data/filter/hooks/useFilterStates.ts b/front/src/modules/ui/data/filter/hooks/useFilterStates.ts new file mode 100644 index 000000000..6dc39a724 --- /dev/null +++ b/front/src/modules/ui/data/filter/hooks/useFilterStates.ts @@ -0,0 +1,64 @@ +import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2'; + +import { availableFiltersScopedState } from '../states/availableFiltersScopedState'; +import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; +import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; +import { filterDropdownSelectedEntityIdScopedState } from '../states/filterDropdownSelectedEntityIdScopedState'; +import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; +import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState'; +import { selectedFiltersScopedState } from '../states/selectedFiltersScopedState'; +import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; + +export const useFilterStates = (scopeId: string) => { + const [availableFilters, setAvailableFilters] = useRecoilScopedStateV2( + availableFiltersScopedState, + scopeId, + ); + + const [filterDefinitionUsedInDropdown, setFilterDefinitionUsedInDropdown] = + useRecoilScopedStateV2(filterDefinitionUsedInDropdownScopedState, scopeId); + + const [filterDropdownSearchInput, setFilterDropdownSearchInput] = + useRecoilScopedStateV2(filterDropdownSearchInputScopedState, scopeId); + + const [filterDropdownSelectedEntityId, setFilterDropdownSelectedEntityId] = + useRecoilScopedStateV2(filterDropdownSelectedEntityIdScopedState, scopeId); + + const [ + isFilterDropdownOperandSelectUnfolded, + setIsFilterDropdownOperandSelectUnfolded, + ] = useRecoilScopedStateV2( + isFilterDropdownOperandSelectUnfoldedScopedState, + scopeId, + ); + + const [isFilterDropdownUnfolded, setIsFilterDropdownUnfolded] = + useRecoilScopedStateV2(isFilterDropdownUnfoldedScopedState, scopeId); + + const [selectedFilters, setSelectedFilters] = useRecoilScopedStateV2( + selectedFiltersScopedState, + scopeId, + ); + + const [selectedOperandInDropdown, setSelectedOperandInDropdown] = + useRecoilScopedStateV2(selectedOperandInDropdownScopedState, scopeId); + + return { + availableFilters, + setAvailableFilters, + filterDefinitionUsedInDropdown, + setFilterDefinitionUsedInDropdown, + filterDropdownSearchInput, + setFilterDropdownSearchInput, + filterDropdownSelectedEntityId, + setFilterDropdownSelectedEntityId, + isFilterDropdownOperandSelectUnfolded, + setIsFilterDropdownOperandSelectUnfolded, + isFilterDropdownUnfolded, + setIsFilterDropdownUnfolded, + selectedFilters, + setSelectedFilters, + selectedOperandInDropdown, + setSelectedOperandInDropdown, + }; +}; diff --git a/front/src/modules/ui/data/filter/scopes/FilterScope.tsx b/front/src/modules/ui/data/filter/scopes/FilterScope.tsx new file mode 100644 index 000000000..594554156 --- /dev/null +++ b/front/src/modules/ui/data/filter/scopes/FilterScope.tsx @@ -0,0 +1,28 @@ +import { ReactNode } from 'react'; + +import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition'; + +import { FilterScopeInitEffect } from './init-effect/FilterScopeInitEffect'; +import { FilterScopeInternalContext } from './scope-internal-context/FilterScopeInternalContext'; + +type FilterScopeProps = { + children: ReactNode; + filterScopeId: string; + availableFilters?: FilterDefinition[]; +}; + +export const FilterScope = ({ + children, + filterScopeId, + availableFilters, +}: FilterScopeProps) => { + return ( + + + {children} + + ); +}; diff --git a/front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx b/front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx new file mode 100644 index 000000000..1068f1797 --- /dev/null +++ b/front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx @@ -0,0 +1,25 @@ +import { useEffect } from 'react'; + +import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition'; + +import { useFilterStates } from '../../hooks/useFilterStates'; + +type FilterScopeInitEffectProps = { + filterScopeId: string; + availableFilters?: FilterDefinition[]; +}; + +export const FilterScopeInitEffect = ({ + filterScopeId, + availableFilters, +}: FilterScopeInitEffectProps) => { + const { setAvailableFilters } = useFilterStates(filterScopeId); + + useEffect(() => { + if (availableFilters) { + setAvailableFilters(availableFilters); + } + }, [availableFilters, setAvailableFilters]); + + return <>; +}; diff --git a/front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts b/front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts new file mode 100644 index 000000000..e45d8d6ae --- /dev/null +++ b/front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts @@ -0,0 +1,9 @@ +import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey'; +import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; + +type FilterScopeInternalContextProps = ScopedStateKey & { + test?: string; +}; + +export const FilterScopeInternalContext = + createScopeInternalContext(); diff --git a/front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts b/front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts new file mode 100644 index 000000000..9c38f3952 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts @@ -0,0 +1,9 @@ +import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition'; +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const availableFiltersScopedState = createScopedState< + FilterDefinition[] +>({ + key: 'availableFiltersScopedState', + defaultValue: [], +}); diff --git a/front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts b/front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts new file mode 100644 index 000000000..c848f4052 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts @@ -0,0 +1,9 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +import { FilterDefinition } from '../types/FilterDefinition'; + +export const filterDefinitionUsedInDropdownScopedState = + createScopedState({ + key: 'filterDefinitionUsedInDropdownScopedState', + defaultValue: null, + }); diff --git a/front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts b/front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts new file mode 100644 index 000000000..b81c820e5 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts @@ -0,0 +1,6 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const filterDropdownSearchInputScopedState = createScopedState({ + key: 'filterDropdownSearchInputScopedState', + defaultValue: '', +}); diff --git a/front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts b/front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts new file mode 100644 index 000000000..799c06481 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts @@ -0,0 +1,8 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const filterDropdownSelectedEntityIdScopedState = createScopedState< + string | null +>({ + key: 'filterDropdownSelectedEntityIdScopedState', + defaultValue: null, +}); diff --git a/front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts b/front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts new file mode 100644 index 000000000..3bda55bdf --- /dev/null +++ b/front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts @@ -0,0 +1,7 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const isFilterDropdownOperandSelectUnfoldedScopedState = + createScopedState({ + key: 'isFilterDropdownOperandSelectUnfoldedScopedState', + defaultValue: false, + }); diff --git a/front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts b/front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts new file mode 100644 index 000000000..57799a876 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts @@ -0,0 +1,6 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const isFilterDropdownUnfoldedScopedState = createScopedState({ + key: 'isFilterDropdownUnfoldedScopedState', + defaultValue: false, +}); diff --git a/front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts b/front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts new file mode 100644 index 000000000..716548451 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts @@ -0,0 +1,8 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +import { Filter } from '../types/Filter'; + +export const selectedFiltersScopedState = createScopedState({ + key: 'selectedFiltersScopedState', + defaultValue: [], +}); diff --git a/front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts b/front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts new file mode 100644 index 000000000..ee96c8ab3 --- /dev/null +++ b/front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts @@ -0,0 +1,8 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; +import { ViewFilterOperand } from '~/generated/graphql'; + +export const selectedOperandInDropdownScopedState = + createScopedState({ + key: 'selectedOperandInDropdownScopedState', + defaultValue: null, + }); diff --git a/front/src/modules/ui/data/view-bar/states/selectors/filtersWhereScopedSelector.ts b/front/src/modules/ui/data/filter/states/selectors/filtersWhereScopedSelector.ts similarity index 55% rename from front/src/modules/ui/data/view-bar/states/selectors/filtersWhereScopedSelector.ts rename to front/src/modules/ui/data/filter/states/selectors/filtersWhereScopedSelector.ts index e23d517d0..a52dc4c14 100644 --- a/front/src/modules/ui/data/view-bar/states/selectors/filtersWhereScopedSelector.ts +++ b/front/src/modules/ui/data/filter/states/selectors/filtersWhereScopedSelector.ts @@ -1,13 +1,15 @@ import { selectorFamily } from 'recoil'; import { turnFilterIntoWhereClause } from '../../utils/turnFilterIntoWhereClause'; -import { filtersScopedState } from '../filtersScopedState'; +import { selectedFiltersScopedState } from '../selectedFiltersScopedState'; export const filtersWhereScopedSelector = selectorFamily({ key: 'filtersWhereScopedSelector', get: - (param: string) => + (scopeId: string) => ({ get }) => ({ - AND: get(filtersScopedState(param)).map(turnFilterIntoWhereClause), + AND: get(selectedFiltersScopedState({ scopeId })).map( + turnFilterIntoWhereClause, + ), }), }); diff --git a/front/src/modules/ui/data/view-bar/types/Filter.ts b/front/src/modules/ui/data/filter/types/Filter.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/Filter.ts rename to front/src/modules/ui/data/filter/types/Filter.ts diff --git a/front/src/modules/ui/data/view-bar/types/FilterDefinition.ts b/front/src/modules/ui/data/filter/types/FilterDefinition.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/FilterDefinition.ts rename to front/src/modules/ui/data/filter/types/FilterDefinition.ts diff --git a/front/src/modules/ui/data/view-bar/types/FilterDefinitionByEntity.ts b/front/src/modules/ui/data/filter/types/FilterDefinitionByEntity.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/FilterDefinitionByEntity.ts rename to front/src/modules/ui/data/filter/types/FilterDefinitionByEntity.ts diff --git a/front/src/modules/ui/data/view-bar/types/FilterOperand.ts b/front/src/modules/ui/data/filter/types/FilterOperand.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/FilterOperand.ts rename to front/src/modules/ui/data/filter/types/FilterOperand.ts diff --git a/front/src/modules/ui/data/view-bar/types/FilterType.ts b/front/src/modules/ui/data/filter/types/FilterType.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/FilterType.ts rename to front/src/modules/ui/data/filter/types/FilterType.ts diff --git a/front/src/modules/ui/data/view-bar/types/FiltersHotkeyScope.ts b/front/src/modules/ui/data/filter/types/FiltersHotkeyScope.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/FiltersHotkeyScope.ts rename to front/src/modules/ui/data/filter/types/FiltersHotkeyScope.ts diff --git a/front/src/modules/ui/data/view-bar/utils/getOperandLabel.ts b/front/src/modules/ui/data/filter/utils/getOperandLabel.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/utils/getOperandLabel.ts rename to front/src/modules/ui/data/filter/utils/getOperandLabel.ts diff --git a/front/src/modules/ui/data/view-bar/utils/getOperandsForFilterType.ts b/front/src/modules/ui/data/filter/utils/getOperandsForFilterType.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/utils/getOperandsForFilterType.ts rename to front/src/modules/ui/data/filter/utils/getOperandsForFilterType.ts diff --git a/front/src/modules/ui/data/view-bar/utils/turnFilterIntoWhereClause.ts b/front/src/modules/ui/data/filter/utils/turnFilterIntoWhereClause.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/utils/turnFilterIntoWhereClause.ts rename to front/src/modules/ui/data/filter/utils/turnFilterIntoWhereClause.ts diff --git a/front/src/modules/ui/data/view-bar/components/SortDropdownButton.tsx b/front/src/modules/ui/data/sort/components/SortDropdownButton.tsx similarity index 74% rename from front/src/modules/ui/data/view-bar/components/SortDropdownButton.tsx rename to front/src/modules/ui/data/sort/components/SortDropdownButton.tsx index 8d7e23bbf..10e59ee64 100644 --- a/front/src/modules/ui/data/view-bar/components/SortDropdownButton.tsx +++ b/front/src/modules/ui/data/sort/components/SortDropdownButton.tsx @@ -1,5 +1,4 @@ import { useCallback, useState } from 'react'; -import { produce } from 'immer'; import { IconChevronDown } from '@/ui/display/icon'; import { LightButton } from '@/ui/input/button/components/LightButton'; @@ -11,12 +10,9 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { SortDropdownId } from '../constants/SortDropdownId'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { availableSortsScopedState } from '../states/availableSortsScopedState'; -import { sortsScopedState } from '../states/sortsScopedState'; +import { useSort } from '../hooks/useSort'; import { SortDefinition } from '../types/SortDefinition'; import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection'; @@ -28,8 +24,6 @@ export type SortDropdownButtonProps = { export const SortDropdownButton = ({ hotkeyScope, }: SortDropdownButtonProps) => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - const [isSortDirectionMenuUnfolded, setIsSortDirectionMenuUnfolded] = useState(false); @@ -41,17 +35,7 @@ export const SortDropdownButton = ({ setSelectedSortDirection('asc'); }, []); - const [availableSorts] = useRecoilScopedState( - availableSortsScopedState, - ViewBarRecoilScopeContext, - ); - - const [sorts, setSorts] = useRecoilScopedState( - sortsScopedState, - ViewBarRecoilScopeContext, - ); - - const isSortSelected = sorts.length > 0; + const { availableSorts, onSortAdd, isSortSelected } = useSort(); const { toggleDropdown } = useDropdown({ dropdownScopeId: SortDropdownId, @@ -64,25 +48,11 @@ export const SortDropdownButton = ({ const handleAddSort = (selectedSortDefinition: SortDefinition) => { toggleDropdown(); - - setSorts( - produce(sorts, (existingSortsDraft) => { - const foundExistingSortIndex = existingSortsDraft.findIndex( - (existingSort) => existingSort.key === selectedSortDefinition.key, - ); - - if (foundExistingSortIndex !== -1) { - existingSortsDraft[foundExistingSortIndex].direction = - selectedSortDirection; - } else { - existingSortsDraft.push({ - key: selectedSortDefinition.key, - direction: selectedSortDirection, - definition: selectedSortDefinition, - }); - } - }), - ); + onSortAdd?.({ + key: selectedSortDefinition.key, + direction: selectedSortDirection, + definition: selectedSortDefinition, + }); }; const handleDropdownButtonClose = () => { diff --git a/front/src/modules/ui/data/view-bar/constants/SortDropdownId.ts b/front/src/modules/ui/data/sort/constants/SortDropdownId.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/constants/SortDropdownId.ts rename to front/src/modules/ui/data/sort/constants/SortDropdownId.ts diff --git a/front/src/modules/ui/data/sort/hooks/useSort.ts b/front/src/modules/ui/data/sort/hooks/useSort.ts new file mode 100644 index 000000000..2559f8fcf --- /dev/null +++ b/front/src/modules/ui/data/sort/hooks/useSort.ts @@ -0,0 +1,36 @@ +import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId'; + +import { SortScopeInternalContext } from '../scopes/scope-internal-context/SortScopeInternalContext'; + +import { useScopeInternalContextOrThrow } from './../../../utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContextOrThrow'; +import { useSortStates } from './useSortStates'; + +type UseSortProps = { + sortScopeId?: string; +}; + +export const useSort = (props?: UseSortProps) => { + const scopeId = useAvailableScopeIdOrThrow( + SortScopeInternalContext, + props?.sortScopeId, + ); + const { + availableSorts, + setAvailableSorts, + isSortSelected, + setIsSortSelected, + } = useSortStates(scopeId); + + const { onSortAdd } = useScopeInternalContextOrThrow( + SortScopeInternalContext, + ); + + return { + onSortAdd, + scopeId, + availableSorts, + isSortSelected, + setIsSortSelected, + setAvailableSorts, + }; +}; diff --git a/front/src/modules/ui/data/sort/hooks/useSortStates.ts b/front/src/modules/ui/data/sort/hooks/useSortStates.ts new file mode 100644 index 000000000..78d94081e --- /dev/null +++ b/front/src/modules/ui/data/sort/hooks/useSortStates.ts @@ -0,0 +1,23 @@ +import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2'; +import { availableSortsScopedState } from '@/views/states/availableSortsScopedState'; + +import { isSortSelectedScopedState } from '../states/isSortSelectedScopedState'; + +export const useSortStates = (scopeId: string) => { + const [availableSorts, setAvailableSorts] = useRecoilScopedStateV2( + availableSortsScopedState, + scopeId, + ); + + const [isSortSelected, setIsSortSelected] = useRecoilScopedStateV2( + isSortSelectedScopedState, + scopeId, + ); + + return { + availableSorts, + setAvailableSorts, + isSortSelected, + setIsSortSelected, + }; +}; diff --git a/front/src/modules/ui/data/sort/scopes/SortScope.tsx b/front/src/modules/ui/data/sort/scopes/SortScope.tsx new file mode 100644 index 000000000..0b511fd1b --- /dev/null +++ b/front/src/modules/ui/data/sort/scopes/SortScope.tsx @@ -0,0 +1,33 @@ +import { ReactNode } from 'react'; + +import { Sort } from '../types/Sort'; +import { SortDefinition } from '../types/SortDefinition'; + +import { SortScopeInitEffect } from './init-effect/SortScopeInitEffect'; +import { SortScopeInternalContext } from './scope-internal-context/SortScopeInternalContext'; + +type SortScopeProps = { + children: ReactNode; + sortScopeId: string; + availableSorts?: SortDefinition[]; + onSortAdd?: (sort: Sort) => void | Promise; +}; + +export const SortScope = ({ + children, + sortScopeId, + availableSorts, + onSortAdd, +}: SortScopeProps) => { + return ( + + + {children} + + ); +}; diff --git a/front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx b/front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx new file mode 100644 index 000000000..a4a41a390 --- /dev/null +++ b/front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx @@ -0,0 +1,25 @@ +import { useEffect } from 'react'; + +import { SortDefinition } from '@/ui/data/sort/types/SortDefinition'; + +import { useSortStates } from '../../hooks/useSortStates'; + +type SortScopeInitEffectProps = { + sortScopeId: string; + availableSorts?: SortDefinition[]; +}; + +export const SortScopeInitEffect = ({ + sortScopeId, + availableSorts, +}: SortScopeInitEffectProps) => { + const { setAvailableSorts } = useSortStates(sortScopeId); + + useEffect(() => { + if (availableSorts) { + setAvailableSorts(availableSorts); + } + }, [availableSorts, setAvailableSorts]); + + return <>; +}; diff --git a/front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts b/front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts new file mode 100644 index 000000000..d8022b55b --- /dev/null +++ b/front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts @@ -0,0 +1,13 @@ +import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey'; +import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext'; + +import { Sort } from '../../types/Sort'; +import { SortDefinition } from '../../types/SortDefinition'; + +type SortScopeInternalContextProps = ScopedStateKey & { + onSortAdd?: (sort: Sort) => void; + availableSorts?: SortDefinition[]; +}; + +export const SortScopeInternalContext = + createScopeInternalContext(); diff --git a/front/src/modules/ui/data/sort/states/availableSortsScopedState.ts b/front/src/modules/ui/data/sort/states/availableSortsScopedState.ts new file mode 100644 index 000000000..1e8354cdb --- /dev/null +++ b/front/src/modules/ui/data/sort/states/availableSortsScopedState.ts @@ -0,0 +1,8 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +import { SortDefinition } from '../types/SortDefinition'; + +export const availableSortsScopedState = createScopedState({ + key: 'availableSortsScopedState', + defaultValue: [], +}); diff --git a/front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts b/front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts new file mode 100644 index 000000000..b377baea8 --- /dev/null +++ b/front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts @@ -0,0 +1,6 @@ +import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState'; + +export const isSortSelectedScopedState = createScopedState({ + key: 'isSortSelectedScopedState', + defaultValue: false, +}); diff --git a/front/src/modules/ui/data/view-bar/types/Sort.ts b/front/src/modules/ui/data/sort/types/Sort.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/Sort.ts rename to front/src/modules/ui/data/sort/types/Sort.ts diff --git a/front/src/modules/ui/data/view-bar/types/SortDefinition.ts b/front/src/modules/ui/data/sort/types/SortDefinition.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/SortDefinition.ts rename to front/src/modules/ui/data/sort/types/SortDefinition.ts diff --git a/front/src/modules/ui/data/view-bar/types/SortDirection.ts b/front/src/modules/ui/data/sort/types/SortDirection.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/SortDirection.ts rename to front/src/modules/ui/data/sort/types/SortDirection.ts diff --git a/front/src/modules/ui/data/view-bar/types/interface.ts b/front/src/modules/ui/data/sort/types/interface.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/types/interface.ts rename to front/src/modules/ui/data/sort/types/interface.ts diff --git a/front/src/modules/ui/data/view-bar/utils/helpers.ts b/front/src/modules/ui/data/sort/utils/helpers.ts similarity index 100% rename from front/src/modules/ui/data/view-bar/utils/helpers.ts rename to front/src/modules/ui/data/sort/utils/helpers.ts diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx deleted file mode 100644 index 0541e0223..000000000 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useUpsertFilter } from '@/ui/data/view-bar/hooks/useUpsertFilter'; -import { filterDefinitionUsedInDropdownScopedState } from '@/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState'; -import { selectedOperandInDropdownScopedState } from '@/ui/data/view-bar/states/selectedOperandInDropdownScopedState'; -import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; - -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState'; - -export const FilterDropdownDateSearchInput = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setIsFilterDropdownUnfolded] = useRecoilScopedState( - isFilterDropdownUnfoldedScopedState, - ViewBarRecoilScopeContext, - ); - - const upsertFilter = useUpsertFilter(); - - const handleChange = (date: Date) => { - if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; - - upsertFilter({ - key: filterDefinitionUsedInDropdown.key, - type: filterDefinitionUsedInDropdown.type, - value: date.toISOString(), - operand: selectedOperandInDropdown, - displayValue: date.toLocaleDateString(), - }); - - setIsFilterDropdownUnfolded(false); - }; - - return ( - - ); -}; diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx deleted file mode 100644 index d6b118b38..000000000 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { ChangeEvent } from 'react'; - -import { filterDefinitionUsedInDropdownScopedState } from '@/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState'; -import { selectedOperandInDropdownScopedState } from '@/ui/data/view-bar/states/selectedOperandInDropdownScopedState'; -import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; - -import { useViewBarContext } from '../hooks/useViewBarContext'; - -export const FilterDropdownEntitySearchInput = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [filterDropdownSearchInput, setFilterDropdownSearchInput] = - useRecoilScopedState( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - - return ( - filterDefinitionUsedInDropdown && - selectedOperandInDropdown && ( - ) => { - setFilterDropdownSearchInput(event.target.value); - }} - /> - ) - ); -}; diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx deleted file mode 100644 index 4e5384dd1..000000000 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; - -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; - -export const FilterDropdownEntitySelect = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [filterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - if (filterDefinitionUsedInDropdown?.type !== 'entity') { - return null; - } - - return ( - <> - - - {filterDefinitionUsedInDropdown.entitySelectComponent} - - - ); -}; diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx deleted file mode 100644 index 33eb3fd77..000000000 --- a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { IconChevronDown } from '@/ui/display/icon'; -import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; - -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; -import { getOperandLabel } from '../utils/getOperandLabel'; - -export const FilterDropdownOperandButton = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const [selectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [ - isFilterDropdownOperandSelectUnfolded, - setIsFilterDropdownOperandSelectUnfolded, - ] = useRecoilScopedState( - isFilterDropdownOperandSelectUnfoldedScopedState, - ViewBarRecoilScopeContext, - ); - - if (isFilterDropdownOperandSelectUnfolded) { - return null; - } - - return ( - setIsFilterDropdownOperandSelectUnfolded(true)} - > - {getOperandLabel(selectedOperandInDropdown)} - - ); -}; diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx b/front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx deleted file mode 100644 index ad5cce81c..000000000 --- a/front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; -import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; -import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; - -import { FilterDropdownId } from '../constants/FilterDropdownId'; -import { useViewBarContext } from '../hooks/useViewBarContext'; -import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState'; -import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState'; -import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState'; -import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState'; - -export const MultipleFiltersButton = () => { - const { ViewBarRecoilScopeContext } = useViewBarContext(); - - const { isDropdownOpen, toggleDropdown } = useDropdown({ - dropdownScopeId: FilterDropdownId, - }); - - const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState( - isFilterDropdownOperandSelectUnfoldedScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState( - filterDefinitionUsedInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setFilterDropdownSearchInput] = useRecoilScopedState( - filterDropdownSearchInputScopedState, - ViewBarRecoilScopeContext, - ); - - const [, setSelectedOperandInDropdown] = useRecoilScopedState( - selectedOperandInDropdownScopedState, - ViewBarRecoilScopeContext, - ); - - const resetState = () => { - setIsFilterDropdownOperandSelectUnfolded(false); - setFilterDefinitionUsedInDropdown(null); - setSelectedOperandInDropdown(null); - setFilterDropdownSearchInput(''); - }; - - const handleClick = () => { - toggleDropdown(); - resetState(); - }; - - return ( - - Filter - - ); -}; diff --git a/front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx b/front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx deleted file mode 100644 index 443602cb9..000000000 --- a/front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { useCallback, useContext, useState } from 'react'; -import styled from '@emotion/styled'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { Key } from 'ts-key-enum'; - -import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState'; -import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState'; -import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState'; -import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState'; -import { canPersistFiltersScopedFamilySelector } from '@/ui/data/view-bar/states/selectors/canPersistFiltersScopedFamilySelector'; -import { canPersistSortsScopedFamilySelector } from '@/ui/data/view-bar/states/selectors/canPersistSortsScopedFamilySelector'; -import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState'; -import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState'; -import { IconChevronDown, IconPlus } from '@/ui/display/icon'; -import { Button } from '@/ui/input/button/components/Button'; -import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup'; -import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; -import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; -import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; -import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; -import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId'; - -import { ViewBarContext } from '../contexts/ViewBarContext'; - -const StyledContainer = styled.div` - display: inline-flex; - margin-right: ${({ theme }) => theme.spacing(2)}; - position: relative; -`; -export type UpdateViewButtonGroupProps = { - hotkeyScope: string; - onViewEditModeChange?: () => void; -}; - -export const UpdateViewButtonGroup = ({ - hotkeyScope, - onViewEditModeChange, -}: UpdateViewButtonGroupProps) => { - const [isDropdownOpen, setIsDropdownOpen] = useState(false); - - const { - canPersistViewFields, - onCurrentViewSubmit, - ViewBarRecoilScopeContext, - } = useContext(ViewBarContext); - - const recoilScopeId = useRecoilScopeId(ViewBarRecoilScopeContext); - - const currentViewId = useRecoilScopedValue( - currentViewIdScopedState, - ViewBarRecoilScopeContext, - ); - - const filters = useRecoilScopedValue( - filtersScopedState, - ViewBarRecoilScopeContext, - ); - const setSavedFilters = useSetRecoilState( - savedFiltersFamilyState(currentViewId), - ); - const canPersistFilters = useRecoilValue( - canPersistFiltersScopedFamilySelector({ - recoilScopeId, - viewId: currentViewId, - }), - ); - - const sorts = useRecoilScopedValue( - sortsScopedState, - ViewBarRecoilScopeContext, - ); - const setSavedSorts = useSetRecoilState(savedSortsFamilyState(currentViewId)); - const canPersistSorts = useRecoilValue( - canPersistSortsScopedFamilySelector({ - recoilScopeId, - viewId: currentViewId, - }), - ); - - const setViewEditMode = useSetRecoilState(viewEditModeState); - - const canPersistView = - currentViewId && - (canPersistViewFields || canPersistFilters || canPersistSorts); - - const handleArrowDownButtonClick = useCallback(() => { - setIsDropdownOpen((previousIsOpen) => !previousIsOpen); - }, []); - - const handleCreateViewButtonClick = useCallback(() => { - setViewEditMode({ mode: 'create', viewId: undefined }); - onViewEditModeChange?.(); - setIsDropdownOpen(false); - }, [setViewEditMode, onViewEditModeChange]); - - const handleDropdownClose = useCallback(() => { - setIsDropdownOpen(false); - }, []); - - const handleViewSubmit = async () => { - if (canPersistFilters) setSavedFilters(filters); - if (canPersistSorts) setSavedSorts(sorts); - - await onCurrentViewSubmit?.(); - }; - - useScopedHotkeys( - [Key.Enter, Key.Escape], - handleDropdownClose, - hotkeyScope, - [], - ); - - if (!canPersistView) return null; - - return ( - - -