feat: toggle board field visibilities (#1547)
Closes #1537, Closes #1539
This commit is contained in:
113
front/src/modules/views/hooks/useBoardViewFields.ts
Normal file
113
front/src/modules/views/hooks/useBoardViewFields.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { type Context } from 'react';
|
||||
|
||||
import { availableBoardCardFieldsScopedState } from '@/ui/board/states/availableBoardCardFieldsScopedState';
|
||||
import { boardCardFieldsScopedState } from '@/ui/board/states/boardCardFieldsScopedState';
|
||||
import type {
|
||||
ViewFieldDefinition,
|
||||
ViewFieldMetadata,
|
||||
} from '@/ui/editable-field/types/ViewField';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
|
||||
import {
|
||||
SortOrder,
|
||||
useCreateViewFieldsMutation,
|
||||
useGetViewFieldsQuery,
|
||||
} from '~/generated/graphql';
|
||||
import { assertNotNull } from '~/utils/assert';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
const toViewFieldInput = (
|
||||
objectId: 'company' | 'person',
|
||||
fieldDefinition: ViewFieldDefinition<ViewFieldMetadata>,
|
||||
) => ({
|
||||
key: fieldDefinition.key,
|
||||
name: fieldDefinition.name,
|
||||
index: fieldDefinition.index,
|
||||
isVisible: fieldDefinition.isVisible ?? true,
|
||||
objectId,
|
||||
});
|
||||
|
||||
export const useBoardViewFields = ({
|
||||
objectId,
|
||||
fieldDefinitions,
|
||||
scopeContext,
|
||||
skipFetch,
|
||||
}: {
|
||||
objectId: 'company' | 'person';
|
||||
fieldDefinitions: ViewFieldDefinition<ViewFieldMetadata>[];
|
||||
scopeContext: Context<string | null>;
|
||||
skipFetch?: boolean;
|
||||
}) => {
|
||||
const currentViewId = useRecoilScopedValue(
|
||||
currentViewIdScopedState,
|
||||
scopeContext,
|
||||
);
|
||||
const [availableBoardCardFields, setAvailableBoardCardFields] =
|
||||
useRecoilScopedState(availableBoardCardFieldsScopedState, scopeContext);
|
||||
const [boardCardFields, setBoardCardFields] = useRecoilScopedState(
|
||||
boardCardFieldsScopedState,
|
||||
scopeContext,
|
||||
);
|
||||
|
||||
const [createViewFieldsMutation] = useCreateViewFieldsMutation();
|
||||
|
||||
const createViewFields = (
|
||||
fields: ViewFieldDefinition<ViewFieldMetadata>[],
|
||||
viewId = currentViewId,
|
||||
) => {
|
||||
if (!viewId || !fields.length) return;
|
||||
|
||||
return createViewFieldsMutation({
|
||||
variables: {
|
||||
data: fields.map((field) => ({
|
||||
...toViewFieldInput(objectId, field),
|
||||
viewId,
|
||||
})),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const { refetch } = useGetViewFieldsQuery({
|
||||
skip: !currentViewId || skipFetch,
|
||||
variables: {
|
||||
orderBy: { index: SortOrder.Asc },
|
||||
where: {
|
||||
viewId: { equals: currentViewId },
|
||||
},
|
||||
},
|
||||
onCompleted: async (data) => {
|
||||
if (!data.viewFields.length) {
|
||||
// Populate if empty
|
||||
await createViewFields(fieldDefinitions);
|
||||
return refetch();
|
||||
}
|
||||
|
||||
const nextFields = data.viewFields
|
||||
.map<ViewFieldDefinition<ViewFieldMetadata> | null>((viewField) => {
|
||||
const fieldDefinition = fieldDefinitions.find(
|
||||
({ key }) => viewField.key === key,
|
||||
);
|
||||
|
||||
return fieldDefinition
|
||||
? {
|
||||
...fieldDefinition,
|
||||
key: viewField.key,
|
||||
name: viewField.name,
|
||||
index: viewField.index,
|
||||
isVisible: viewField.isVisible,
|
||||
}
|
||||
: null;
|
||||
})
|
||||
.filter<ViewFieldDefinition<ViewFieldMetadata>>(assertNotNull);
|
||||
|
||||
if (!isDeeplyEqual(boardCardFields, nextFields)) {
|
||||
setBoardCardFields(nextFields);
|
||||
}
|
||||
|
||||
if (!availableBoardCardFields.length) {
|
||||
setAvailableBoardCardFields(fieldDefinitions);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -1,5 +1,9 @@
|
||||
import { type Context } from 'react';
|
||||
import type { Context } from 'react';
|
||||
|
||||
import type {
|
||||
ViewFieldDefinition,
|
||||
ViewFieldMetadata,
|
||||
} from '@/ui/editable-field/types/ViewField';
|
||||
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';
|
||||
@ -7,6 +11,7 @@ import type { FilterDefinitionByEntity } from '@/ui/view-bar/types/FilterDefinit
|
||||
import type { SortType } from '@/ui/view-bar/types/interface';
|
||||
import { ViewType } from '~/generated/graphql';
|
||||
|
||||
import { useBoardViewFields } from './useBoardViewFields';
|
||||
import { useViewFilters } from './useViewFilters';
|
||||
import { useViews } from './useViews';
|
||||
import { useViewSorts } from './useViewSorts';
|
||||
@ -14,11 +19,13 @@ import { useViewSorts } from './useViewSorts';
|
||||
export const useBoardViews = <Entity, SortField>({
|
||||
availableFilters,
|
||||
availableSorts,
|
||||
fieldDefinitions,
|
||||
objectId,
|
||||
scopeContext,
|
||||
}: {
|
||||
availableFilters: FilterDefinitionByEntity<Entity>[];
|
||||
availableSorts: SortType<SortField>[];
|
||||
fieldDefinitions: ViewFieldDefinition<ViewFieldMetadata>[];
|
||||
objectId: 'company';
|
||||
scopeContext: Context<string | null>;
|
||||
}) => {
|
||||
@ -31,6 +38,12 @@ export const useBoardViews = <Entity, SortField>({
|
||||
type: ViewType.Pipeline,
|
||||
scopeContext,
|
||||
});
|
||||
useBoardViewFields({
|
||||
objectId,
|
||||
fieldDefinitions,
|
||||
scopeContext,
|
||||
skipFetch: isFetchingViews,
|
||||
});
|
||||
const { createViewFilters, persistFilters } = useViewFilters({
|
||||
availableFilters,
|
||||
scopeContext,
|
||||
|
||||
Reference in New Issue
Block a user