feat: add Opportunities Views dropdown (#1503)

* feat: add Opportunities Views dropdown

Closes #1454

* feat: persist Opportunities view filters and sorts

Closes #1456

* feat: create/edit/delete Opportunities views

Closes #1455, Closes #1457

* fix: add missing Opportunities view mock

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
Thaïs
2023-09-11 04:07:14 +02:00
committed by GitHub
parent 8ea4e6a51c
commit 88c6d0da2a
14 changed files with 408 additions and 225 deletions

View File

@ -0,0 +1,56 @@
import { type Context } from 'react';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
import type { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinitionByEntity';
import type { SortType } from '@/ui/view-bar/types/interface';
import { ViewType } from '~/generated/graphql';
import { useViewFilters } from './useViewFilters';
import { useViews } from './useViews';
import { useViewSorts } from './useViewSorts';
export const useBoardViews = <Entity, SortField>({
availableFilters,
availableSorts,
objectId,
scopeContext,
}: {
availableFilters: FilterDefinitionByEntity<Entity>[];
availableSorts: SortType<SortField>[];
objectId: 'company';
scopeContext: Context<string | null>;
}) => {
const filters = useRecoilScopedValue(filtersScopedState, scopeContext);
const sorts = useRecoilScopedValue(sortsScopedState, scopeContext);
const { handleViewsChange, isFetchingViews } = useViews({
objectId,
onViewCreate: handleViewCreate,
type: ViewType.Pipeline,
scopeContext,
});
const { createViewFilters, persistFilters } = useViewFilters({
availableFilters,
scopeContext,
skipFetch: isFetchingViews,
});
const { createViewSorts, persistSorts } = useViewSorts({
availableSorts,
scopeContext,
skipFetch: isFetchingViews,
});
async function handleViewCreate(viewId: string) {
await createViewFilters(filters, viewId);
await createViewSorts(sorts, viewId);
}
const handleViewSubmit = async () => {
await persistFilters();
await persistSorts();
};
return { handleViewsChange, handleViewSubmit };
};

View File

@ -1,5 +1,3 @@
import { useCallback } from 'react';
import type { ViewFieldMetadata } from '@/ui/editable-field/types/ViewField';
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { tableColumnsScopedState } from '@/ui/table/states/tableColumnsScopedState';
@ -41,6 +39,7 @@ export const useTableViews = <Entity, SortField>({
objectId,
onViewCreate: handleViewCreate,
type: ViewType.Table,
scopeContext: TableRecoilScopeContext,
});
const { createViewFields, persistColumns } = useTableViewFields({
objectId,
@ -64,11 +63,11 @@ export const useTableViews = <Entity, SortField>({
await createViewSorts(sorts, viewId);
}
const handleViewSubmit = useCallback(async () => {
const handleViewSubmit = async () => {
await persistColumns();
await persistFilters();
await persistSorts();
}, [persistColumns, persistFilters, persistSorts]);
};
return { handleViewsChange, handleViewSubmit };
};

View File

@ -1,6 +1,6 @@
import type { Context } from 'react';
import { useRecoilCallback } from 'recoil';
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { savedTableColumnsFamilyState } from '@/ui/table/states/savedTableColumnsFamilyState';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
@ -9,7 +9,7 @@ import { savedFiltersFamilyState } from '@/ui/view-bar/states/savedFiltersFamily
import { savedSortsFamilyState } from '@/ui/view-bar/states/savedSortsFamilyState';
import { viewsByIdScopedSelector } from '@/ui/view-bar/states/selectors/viewsByIdScopedSelector';
import { viewsScopedState } from '@/ui/view-bar/states/viewsScopedState';
import { View } from '@/ui/view-bar/types/View';
import type { View } from '@/ui/view-bar/types/View';
import {
useCreateViewMutation,
useDeleteViewMutation,
@ -22,24 +22,23 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const useViews = ({
objectId,
onViewCreate,
scopeContext,
type,
}: {
objectId: 'company' | 'person';
onViewCreate: (viewId: string) => Promise<void>;
onViewCreate?: (viewId: string) => Promise<void>;
scopeContext: Context<string | null>;
type: ViewType;
}) => {
const [currentViewId, setCurrentViewId] = useRecoilScopedState(
currentViewIdScopedState,
TableRecoilScopeContext,
scopeContext,
);
const [views, setViews] = useRecoilScopedState(
viewsScopedState,
TableRecoilScopeContext,
);
const viewsById = useRecoilScopedValue(
viewsByIdScopedSelector,
TableRecoilScopeContext,
scopeContext,
);
const viewsById = useRecoilScopedValue(viewsByIdScopedSelector, scopeContext);
const [createViewMutation] = useCreateViewMutation();
const [updateViewMutation] = useUpdateViewMutation();
@ -51,12 +50,12 @@ export const useViews = ({
data: {
...view,
objectId,
type: ViewType.Table,
type,
},
},
});
if (data?.view) await onViewCreate(data.view.id);
if (data?.view) await onViewCreate?.(data.view.id);
};
const updateView = (view: View) =>
@ -97,15 +96,22 @@ export const useViews = ({
if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
// If there is no current view selected,
// or if the current view cannot be found in the views list (user switched workspaces)
if (
nextViews.length &&
(!currentViewId || !nextViews.some((view) => view.id === currentViewId))
) {
setCurrentViewId(nextViews[0].id);
handleResetSavedViews();
}
if (!nextViews.length) return;
if (!currentViewId) return setCurrentViewId(nextViews[0].id);
const currentViewExists = nextViews.some(
(view) => view.id === currentViewId,
);
if (currentViewExists) return;
// currentView does not exist in the list = the user has switched workspaces
// and currentViewId is outdated.
// Select the first view in the list.
setCurrentViewId(nextViews[0].id);
// Reset outdated view recoil states.
handleResetSavedViews();
},
});