feat: create view from selected filters and sorts + switch to newly created view on view creation (#1301)
* feat: create view from selected filters and sorts Closes #1292 * refactor: use selector to obtain table filters where query option * refactor: activate exhaustive deps eslint rule for useRecoilCallback * feat: switch to newly created view on view creation Closes #1297 * refactor: code review - use `useCallback` instead of `useRecoilCallback` - rename `useTableViews` to `useViews` - move filter-n-sort selectors to /states/selector subfolder
This commit is contained in:
@ -2,8 +2,8 @@ import { useCallback } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
||||
import { savedFiltersByKeyScopedSelector } from '@/ui/filter-n-sort/states/savedFiltersByKeyScopedSelector';
|
||||
import { savedFiltersScopedState } from '@/ui/filter-n-sort/states/savedFiltersScopedState';
|
||||
import { savedFiltersByKeyScopedSelector } from '@/ui/filter-n-sort/states/selectors/savedFiltersByKeyScopedSelector';
|
||||
import type { Filter } from '@/ui/filter-n-sort/types/Filter';
|
||||
import type { FilterDefinitionByEntity } from '@/ui/filter-n-sort/types/FilterDefinitionByEntity';
|
||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
@ -74,8 +74,8 @@ export const useViewFilters = <Entity>({
|
||||
const [deleteViewFiltersMutation] = useDeleteViewFiltersMutation();
|
||||
|
||||
const createViewFilters = useCallback(
|
||||
(filters: Filter[]) => {
|
||||
if (!currentViewId || !filters.length) return;
|
||||
(filters: Filter[], viewId = currentViewId) => {
|
||||
if (!viewId || !filters.length) return;
|
||||
|
||||
return createViewFiltersMutation({
|
||||
variables: {
|
||||
@ -87,7 +87,7 @@ export const useViewFilters = <Entity>({
|
||||
'',
|
||||
operand: filter.operand,
|
||||
value: filter.value,
|
||||
viewId: currentViewId,
|
||||
viewId,
|
||||
})),
|
||||
},
|
||||
});
|
||||
@ -168,5 +168,5 @@ export const useViewFilters = <Entity>({
|
||||
refetch,
|
||||
]);
|
||||
|
||||
return { persistFilters };
|
||||
return { createViewFilters, persistFilters };
|
||||
};
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { savedSortsByKeyScopedSelector } from '@/ui/filter-n-sort/states/savedSortsByKeyScopedSelector';
|
||||
import { savedSortsScopedState } from '@/ui/filter-n-sort/states/savedSortsScopedState';
|
||||
import { savedSortsByKeyScopedSelector } from '@/ui/filter-n-sort/states/selectors/savedSortsByKeyScopedSelector';
|
||||
import { sortsScopedState } from '@/ui/filter-n-sort/states/sortsScopedState';
|
||||
import type {
|
||||
SelectedSortType,
|
||||
@ -77,8 +77,8 @@ export const useViewSorts = <SortField>({
|
||||
const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
|
||||
|
||||
const createViewSorts = useCallback(
|
||||
(sorts: SelectedSortType<SortField>[]) => {
|
||||
if (!currentViewId || !sorts.length) return;
|
||||
(sorts: SelectedSortType<SortField>[], viewId = currentViewId) => {
|
||||
if (!viewId || !sorts.length) return;
|
||||
|
||||
return createViewSortsMutation({
|
||||
variables: {
|
||||
@ -86,7 +86,7 @@ export const useViewSorts = <SortField>({
|
||||
key: sort.key,
|
||||
direction: sort.order as ViewSortDirection,
|
||||
name: sort.label,
|
||||
viewId: currentViewId,
|
||||
viewId,
|
||||
})),
|
||||
},
|
||||
});
|
||||
@ -162,5 +162,5 @@ export const useViewSorts = <SortField>({
|
||||
refetch,
|
||||
]);
|
||||
|
||||
return { persistSorts };
|
||||
return { createViewSorts, persistSorts };
|
||||
};
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { useCallback } from 'react';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
|
||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
||||
import { sortsScopedState } from '@/ui/filter-n-sort/states/sortsScopedState';
|
||||
import type { FilterDefinitionByEntity } from '@/ui/filter-n-sort/types/FilterDefinitionByEntity';
|
||||
import type { SortType } from '@/ui/filter-n-sort/types/interface';
|
||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
import {
|
||||
type TableView,
|
||||
@ -16,15 +19,21 @@ import {
|
||||
useUpdateViewMutation,
|
||||
ViewType,
|
||||
} from '~/generated/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
import { GET_VIEWS } from '../graphql/queries/getViews';
|
||||
import { useViewFilters } from './useViewFilters';
|
||||
import { useViewSorts } from './useViewSorts';
|
||||
|
||||
export const useTableViews = ({
|
||||
export const useViews = <Entity, SortField>({
|
||||
availableFilters,
|
||||
availableSorts,
|
||||
objectId,
|
||||
}: {
|
||||
availableFilters: FilterDefinitionByEntity<Entity>[];
|
||||
availableSorts: SortType<SortField>[];
|
||||
objectId: 'company' | 'person';
|
||||
}) => {
|
||||
const [, setViews] = useRecoilScopedState(
|
||||
const [views, setViews] = useRecoilScopedState(
|
||||
tableViewsState,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
@ -32,16 +41,27 @@ export const useTableViews = ({
|
||||
tableViewsByIdState,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
const selectedFilters = useRecoilScopedValue(
|
||||
filtersScopedState,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
const selectedSorts = useRecoilScopedValue(
|
||||
sortsScopedState,
|
||||
TableRecoilScopeContext,
|
||||
);
|
||||
|
||||
const [createViewsMutation] = useCreateViewsMutation();
|
||||
const [updateViewMutation] = useUpdateViewMutation();
|
||||
const [deleteViewsMutation] = useDeleteViewsMutation();
|
||||
|
||||
const { createViewFilters } = useViewFilters({ availableFilters });
|
||||
const { createViewSorts } = useViewSorts({ availableSorts });
|
||||
|
||||
const createViews = useCallback(
|
||||
(views: TableView[]) => {
|
||||
async (views: TableView[]) => {
|
||||
if (!views.length) return;
|
||||
|
||||
return createViewsMutation({
|
||||
await createViewsMutation({
|
||||
variables: {
|
||||
data: views.map((view) => ({
|
||||
...view,
|
||||
@ -49,13 +69,26 @@ export const useTableViews = ({
|
||||
type: ViewType.Table,
|
||||
})),
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
views.flatMap((view) => [
|
||||
createViewFilters(selectedFilters, view.id),
|
||||
createViewSorts(selectedSorts, view.id),
|
||||
]),
|
||||
);
|
||||
},
|
||||
[createViewsMutation, objectId],
|
||||
[
|
||||
createViewFilters,
|
||||
createViewSorts,
|
||||
createViewsMutation,
|
||||
objectId,
|
||||
selectedFilters,
|
||||
selectedSorts,
|
||||
],
|
||||
);
|
||||
|
||||
const updateViewFields = useCallback(
|
||||
const updateViews = useCallback(
|
||||
(views: TableView[]) => {
|
||||
if (!views.length) return;
|
||||
|
||||
@ -66,7 +99,6 @@ export const useTableViews = ({
|
||||
data: { name: view.name },
|
||||
where: { id: view.id },
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
|
||||
}),
|
||||
),
|
||||
);
|
||||
@ -84,32 +116,29 @@ export const useTableViews = ({
|
||||
id: { in: viewIds },
|
||||
},
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
|
||||
});
|
||||
},
|
||||
[deleteViewsMutation],
|
||||
);
|
||||
|
||||
useGetViewsQuery({
|
||||
const { refetch } = useGetViewsQuery({
|
||||
variables: {
|
||||
where: {
|
||||
objectId: { equals: objectId },
|
||||
},
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setViews(
|
||||
data.views.map((view) => ({
|
||||
id: view.id,
|
||||
name: view.name,
|
||||
})),
|
||||
);
|
||||
const nextViews = data.views.map((view) => ({
|
||||
id: view.id,
|
||||
name: view.name,
|
||||
}));
|
||||
|
||||
if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
|
||||
},
|
||||
});
|
||||
|
||||
const handleViewsChange = useCallback(
|
||||
async (nextViews: TableView[]) => {
|
||||
setViews(nextViews);
|
||||
|
||||
const viewsToCreate = nextViews.filter(
|
||||
(nextView) => !viewsById[nextView.id],
|
||||
);
|
||||
@ -120,15 +149,17 @@ export const useTableViews = ({
|
||||
viewsById[nextView.id] &&
|
||||
viewsById[nextView.id].name !== nextView.name,
|
||||
);
|
||||
await updateViewFields(viewsToUpdate);
|
||||
await updateViews(viewsToUpdate);
|
||||
|
||||
const nextViewIds = nextViews.map((nextView) => nextView.id);
|
||||
const viewIdsToDelete = Object.keys(viewsById).filter(
|
||||
(previousViewId) => !nextViewIds.includes(previousViewId),
|
||||
);
|
||||
return deleteViews(viewIdsToDelete);
|
||||
await deleteViews(viewIdsToDelete);
|
||||
|
||||
return refetch();
|
||||
},
|
||||
[createViews, deleteViews, setViews, updateViewFields, viewsById],
|
||||
[createViews, deleteViews, refetch, updateViews, viewsById],
|
||||
);
|
||||
|
||||
return { handleViewsChange };
|
||||
Reference in New Issue
Block a user