diff --git a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx index 7ff02c7af..e279270f7 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarDetails.tsx @@ -179,8 +179,8 @@ export const ViewBarDetails = ({ const shouldExpandViewBar = viewFiltersAreDifferentFromRecordFilters || - ((currentViewWithCombinedFiltersAndSorts?.viewSorts?.length || - currentRecordFilters?.length) && + viewSortsAreDifferentFromRecordSorts || + ((currentRecordSorts?.length || currentRecordFilters?.length) && isViewBarExpanded); if (!shouldExpandViewBar) { diff --git a/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts b/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts index b19896b0e..b8517725a 100644 --- a/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts +++ b/packages/twenty-front/src/modules/views/hooks/useAreViewSortsDifferentFromRecordSorts.ts @@ -1,14 +1,46 @@ -import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; +import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; -import { areViewSortsDifferentFromRecordSortsSelector } from '@/views/states/selectors/areViewSortsDifferentFromRecordSortsFamilySelector'; +import { getViewSortsToCreate } from '@/views/utils/getViewSortsToCreate'; +import { getViewSortsToDelete } from '@/views/utils/getViewSortsToDelete'; +import { getViewSortsToUpdate } from '@/views/utils/getViewSortsToUpdate'; +import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort'; +import { useMemo } from 'react'; export const useAreViewSortsDifferentFromRecordSorts = () => { const { currentView } = useGetCurrentViewOnly(); - - const viewSortsAreDifferentFromRecordSorts = useRecoilComponentFamilyValueV2( - areViewSortsDifferentFromRecordSortsSelector, - { viewId: currentView?.id }, + const currentRecordSorts = useRecoilComponentValueV2( + currentRecordSortsComponentState, ); + const viewSortsAreDifferentFromRecordSorts = useMemo(() => { + const currentViewSorts = currentView?.viewSorts ?? []; + const viewSortsFromCurrentRecordSorts = currentRecordSorts.map( + mapRecordSortToViewSort, + ); + + const viewSortsToCreate = getViewSortsToCreate( + currentViewSorts, + viewSortsFromCurrentRecordSorts, + ); + + const viewSortsToDelete = getViewSortsToDelete( + currentViewSorts, + viewSortsFromCurrentRecordSorts, + ); + + const viewSortsToUpdate = getViewSortsToUpdate( + currentViewSorts, + viewSortsFromCurrentRecordSorts, + ); + + const sortsHaveChanged = + viewSortsToCreate.length > 0 || + viewSortsToDelete.length > 0 || + viewSortsToUpdate.length > 0; + + return sortsHaveChanged; + }, [currentRecordSorts, currentView]); + return { viewSortsAreDifferentFromRecordSorts }; }; diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFiltersAndSorts.ts b/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFiltersAndSorts.ts index ef8d7b0e7..0e8020d32 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFiltersAndSorts.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSaveCurrentViewFiltersAndSorts.ts @@ -4,14 +4,12 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/ import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePersistViewFilterGroupRecords'; -import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords'; import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState'; import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates'; import { useSaveRecordFiltersToViewFilters } from '@/views/hooks/useSaveRecordFiltersToViewFilters'; +import { useSaveRecordSortsToViewSorts } from '@/views/hooks/useSaveRecordSortsToViewSorts'; import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState'; -import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState'; import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState'; -import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState'; import { isDefined } from 'twenty-shared'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; @@ -25,18 +23,6 @@ export const useSaveCurrentViewFiltersAndSorts = ( viewBarComponentId, ); - const unsavedToDeleteViewSortIdsCallbackState = - useRecoilComponentCallbackStateV2( - unsavedToDeleteViewSortIdsComponentFamilyState, - viewBarComponentId, - ); - - const unsavedToUpsertViewSortsCallbackState = - useRecoilComponentCallbackStateV2( - unsavedToUpsertViewSortsComponentFamilyState, - viewBarComponentId, - ); - const unsavedToUpsertViewFilterGroupsCallbackState = useRecoilComponentCallbackStateV2( unsavedToUpsertViewFilterGroupsComponentFamilyState, @@ -49,12 +35,6 @@ export const useSaveCurrentViewFiltersAndSorts = ( viewBarComponentId, ); - const { - createViewSortRecords, - updateViewSortRecords, - deleteViewSortRecords, - } = usePersistViewSortRecords(); - const { createViewFilterGroupRecords, deleteViewFilterGroupRecords, @@ -64,52 +44,6 @@ export const useSaveCurrentViewFiltersAndSorts = ( const { resetUnsavedViewStates } = useResetUnsavedViewStates(viewBarComponentId); - const saveViewSorts = useRecoilCallback( - ({ snapshot }) => - async (viewId: string) => { - const unsavedToDeleteViewSortIds = getSnapshotValue( - snapshot, - unsavedToDeleteViewSortIdsCallbackState({ viewId }), - ); - - const unsavedToUpsertViewSorts = getSnapshotValue( - snapshot, - unsavedToUpsertViewSortsCallbackState({ viewId }), - ); - - const view = await getViewFromPrefetchState(viewId); - - if (isUndefinedOrNull(view)) { - return; - } - - const viewSortsToCreate = unsavedToUpsertViewSorts.filter( - (viewSort) => - !view.viewSorts.some( - (vs) => vs.fieldMetadataId === viewSort.fieldMetadataId, - ), - ); - - const viewSortsToUpdate = unsavedToUpsertViewSorts.filter((viewSort) => - view.viewSorts.some( - (vs) => vs.fieldMetadataId === viewSort.fieldMetadataId, - ), - ); - - await createViewSortRecords(viewSortsToCreate, view); - await updateViewSortRecords(viewSortsToUpdate); - await deleteViewSortRecords(unsavedToDeleteViewSortIds); - }, - [ - createViewSortRecords, - deleteViewSortRecords, - getViewFromPrefetchState, - unsavedToDeleteViewSortIdsCallbackState, - unsavedToUpsertViewSortsCallbackState, - updateViewSortRecords, - ], - ); - const saveViewFilterGroups = useRecoilCallback( ({ snapshot }) => async (viewId: string) => { @@ -162,6 +96,8 @@ export const useSaveCurrentViewFiltersAndSorts = ( const { saveRecordFiltersToViewFilters } = useSaveRecordFiltersToViewFilters(); + const { saveRecordSortsToViewSorts } = useSaveRecordSortsToViewSorts(); + const saveCurrentViewFilterAndSorts = useRecoilCallback( ({ snapshot }) => async (viewIdFromProps?: string) => { @@ -176,8 +112,8 @@ export const useSaveCurrentViewFiltersAndSorts = ( const viewId = viewIdFromProps ?? currentViewId; await saveViewFilterGroups(viewId); - await saveViewSorts(viewId); + await saveRecordSortsToViewSorts(); await saveRecordFiltersToViewFilters(); resetUnsavedViewStates(viewId); @@ -185,9 +121,9 @@ export const useSaveCurrentViewFiltersAndSorts = ( [ currentViewIdCallbackState, resetUnsavedViewStates, - saveViewSorts, saveViewFilterGroups, saveRecordFiltersToViewFilters, + saveRecordSortsToViewSorts, ], ); diff --git a/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts b/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts new file mode 100644 index 000000000..bdc7016e0 --- /dev/null +++ b/packages/twenty-front/src/modules/views/hooks/useSaveRecordSortsToViewSorts.ts @@ -0,0 +1,77 @@ +import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState'; +import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; +import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords'; +import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; +import { getViewSortsToCreate } from '@/views/utils/getViewSortsToCreate'; +import { getViewSortsToDelete } from '@/views/utils/getViewSortsToDelete'; +import { getViewSortsToUpdate } from '@/views/utils/getViewSortsToUpdate'; +import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared'; + +export const useSaveRecordSortsToViewSorts = () => { + const { + createViewSortRecords, + updateViewSortRecords, + deleteViewSortRecords, + } = usePersistViewSortRecords(); + + const { currentView } = useGetCurrentViewOnly(); + + const currentRecordSortsCallbackState = useRecoilComponentCallbackStateV2( + currentRecordSortsComponentState, + ); + + const saveRecordSortsToViewSorts = useRecoilCallback( + ({ snapshot }) => + async () => { + if (!isDefined(currentView)) { + return; + } + + const currentViewSorts = currentView?.viewSorts ?? []; + + const currentRecordSorts = getSnapshotValue( + snapshot, + currentRecordSortsCallbackState, + ); + + const newViewSorts = currentRecordSorts.map(mapRecordSortToViewSort); + + const viewSortsToCreate = getViewSortsToCreate( + currentViewSorts, + newViewSorts, + ); + + const viewSortsToDelete = getViewSortsToDelete( + currentViewSorts, + newViewSorts, + ); + + const viewSortsToUpdate = getViewSortsToUpdate( + currentViewSorts, + newViewSorts, + ); + + const viewSortIdsToDelete = viewSortsToDelete.map( + (viewSort) => viewSort.id, + ); + + await createViewSortRecords(viewSortsToCreate, currentView); + await updateViewSortRecords(viewSortsToUpdate); + await deleteViewSortRecords(viewSortIdsToDelete); + }, + [ + createViewSortRecords, + deleteViewSortRecords, + updateViewSortRecords, + currentRecordSortsCallbackState, + currentView, + ], + ); + + return { + saveRecordSortsToViewSorts, + }; +}; diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/areViewSortsEqual.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/areViewSortsEqual.test.ts new file mode 100644 index 000000000..9720133e8 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/__tests__/areViewSortsEqual.test.ts @@ -0,0 +1,40 @@ +import { RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection'; +import { ViewSort } from '@/views/types/ViewSort'; +import { areViewSortsEqual } from '@/views/utils/areViewSortsEqual'; + +describe('areViewSortsEqual', () => { + const baseSort: ViewSort = { + __typename: 'ViewSort', + id: 'sort-1', + fieldMetadataId: 'field-1', + direction: 'asc', + }; + + it('should return true when all comparable properties are equal', () => { + const sortA = { ...baseSort }; + const sortB = { ...baseSort }; + + expect(areViewSortsEqual(sortA, sortB)).toBe(true); + }); + + it('should return false when displayValue is different', () => { + const sortA = { ...baseSort }; + const sortB = { ...baseSort, direction: 'desc' as RecordSortDirection }; + + expect(areViewSortsEqual(sortA, sortB)).toBe(false); + }); + + it('should return false when fieldMetadataId is different', () => { + const sortA = { ...baseSort }; + const sortB = { ...baseSort, fieldMetadataId: 'field-2' }; + + expect(areViewSortsEqual(sortA, sortB)).toBe(false); + }); + + it('should ignore non-comparable properties', () => { + const sortA = { ...baseSort, id: 'id-1', createdAt: '2023-01-01' }; + const sortB = { ...baseSort, id: 'id-2', createdAt: '2023-01-02' }; + + expect(areViewSortsEqual(sortA, sortB)).toBe(true); + }); +}); diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToCreate.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToCreate.test.ts new file mode 100644 index 000000000..ebc8f5790 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToCreate.test.ts @@ -0,0 +1,84 @@ +import { ViewSort } from '@/views/types/ViewSort'; +import { getViewSortsToCreate } from '../getViewSortsToCreate'; + +describe('getViewSortsToCreate', () => { + const baseSort: ViewSort = { + __typename: 'ViewSort', + id: 'sort-1', + fieldMetadataId: 'field-1', + direction: 'asc', + }; + + it('should return all sorts when current sorts array is empty', () => { + const currentViewSorts: ViewSort[] = []; + const newViewSorts: ViewSort[] = [ + { ...baseSort }, + { + ...baseSort, + id: 'sort-2', + fieldMetadataId: 'field-2', + } satisfies ViewSort, + ]; + + const result = getViewSortsToCreate(currentViewSorts, newViewSorts); + + expect(result).toEqual(newViewSorts); + }); + + it('should return empty array when new sorts array is empty', () => { + const currentViewSorts: ViewSort[] = [baseSort]; + const newViewSorts: ViewSort[] = []; + + const result = getViewSortsToCreate(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); + + it('should return only sorts that do not exist in current sorts', () => { + const existingSort = { ...baseSort }; + const newSortWithDifferentFieldMetadataId = { + ...baseSort, + id: 'sort-2', + fieldMetadataId: 'field-2', + } satisfies ViewSort; + + const currentViewSorts: ViewSort[] = [existingSort]; + + const newViewSorts: ViewSort[] = [ + existingSort, + newSortWithDifferentFieldMetadataId, + ]; + + const result = getViewSortsToCreate(currentViewSorts, newViewSorts); + + expect(result).toEqual([newSortWithDifferentFieldMetadataId]); + }); + + it('should handle sorts with different fieldMetadataIds', () => { + const existingSort = { ...baseSort }; + const sortWithDifferentFieldMetadataId = { + ...baseSort, + fieldMetadataId: 'group-2', + } satisfies ViewSort; + + const currentViewSorts: ViewSort[] = [existingSort]; + + const newViewSorts: ViewSort[] = [ + existingSort, + sortWithDifferentFieldMetadataId, + ]; + + const result = getViewSortsToCreate(currentViewSorts, newViewSorts); + + expect(result).toEqual([sortWithDifferentFieldMetadataId]); + }); + + it('should handle empty arrays for both inputs', () => { + const currentViewSorts: ViewSort[] = []; + const newViewSorts: ViewSort[] = []; + + const result = getViewSortsToCreate(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); +}); diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToDelete.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToDelete.test.ts new file mode 100644 index 000000000..42972f74d --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToDelete.test.ts @@ -0,0 +1,72 @@ +import { ViewSort } from '@/views/types/ViewSort'; +import { getViewSortsToDelete } from '../getViewSortsToDelete'; + +describe('getViewSortsToDelete', () => { + const baseSort: ViewSort = { + __typename: 'ViewSort', + id: 'sort-1', + fieldMetadataId: 'field-1', + direction: 'asc', + }; + + it('should return empty array when current sorts array is empty', () => { + const currentViewSorts: ViewSort[] = []; + const newViewSorts: ViewSort[] = [baseSort]; + + const result = getViewSortsToDelete(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); + + it('should return all current sorts when new sorts array is empty', () => { + const existingSort = { ...baseSort }; + const currentViewSorts: ViewSort[] = [existingSort]; + const newViewSorts: ViewSort[] = []; + + const result = getViewSortsToDelete(currentViewSorts, newViewSorts); + + expect(result).toEqual([existingSort]); + }); + + it('should return sorts that exist in current but not in new sorts', () => { + const sortToDelete = { ...baseSort }; + const sortToKeep = { + ...baseSort, + id: 'filter-2', + fieldMetadataId: 'field-2', + } satisfies ViewSort; + + const currentViewSorts: ViewSort[] = [sortToDelete, sortToKeep]; + const newViewSorts: ViewSort[] = [sortToKeep]; + + const result = getViewSortsToDelete(currentViewSorts, newViewSorts); + + expect(result).toEqual([sortToDelete]); + }); + + it('should handle empty arrays for both inputs', () => { + const currentViewSorts: ViewSort[] = []; + const newViewSorts: ViewSort[] = []; + + const result = getViewSortsToDelete(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); + + it('should not delete sorts that match in both fieldMetadataId and direction', () => { + const existingSort = { ...baseSort }; + const matchingSort = { + __typename: 'ViewSort', + id: 'sort-2', + fieldMetadataId: 'field-1', + direction: 'asc', + } satisfies ViewSort; + + const currentViewSorts: ViewSort[] = [existingSort]; + const newViewSorts: ViewSort[] = [matchingSort]; + + const result = getViewSortsToDelete(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); +}); diff --git a/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToUpdate.test.ts b/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToUpdate.test.ts new file mode 100644 index 000000000..5d715fae4 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/__tests__/getViewSortsToUpdate.test.ts @@ -0,0 +1,66 @@ +import { RecordSortDirection } from '@/object-record/record-sort/types/RecordSortDirection'; +import { ViewSort } from '@/views/types/ViewSort'; +import { getViewSortsToUpdate } from '../getViewSortsToUpdate'; + +describe('getViewSortsToUpdate', () => { + const baseSort: ViewSort = { + __typename: 'ViewSort', + id: 'sort-1', + fieldMetadataId: 'field-1', + direction: 'asc' as RecordSortDirection, + }; + + it('should return empty array when current sorts array is empty', () => { + const currentViewSorts: ViewSort[] = []; + const newViewSorts: ViewSort[] = [baseSort]; + + const result = getViewSortsToUpdate(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); + + it('should return empty array when new sorts array is empty', () => { + const currentViewSorts: ViewSort[] = [baseSort]; + const newViewSorts: ViewSort[] = []; + + const result = getViewSortsToUpdate(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); + + it('should return sorts that exist in both arrays but have different direction', () => { + const existingSort = { ...baseSort }; + const updatedSort = { + ...baseSort, + direction: 'desc', + } satisfies ViewSort; + + const currentViewSorts: ViewSort[] = [existingSort]; + const newViewSorts: ViewSort[] = [updatedSort]; + + const result = getViewSortsToUpdate(currentViewSorts, newViewSorts); + + expect(result).toEqual([updatedSort]); + }); + + it('should not return sorts that exist in both arrays with same values', () => { + const existingSort = { ...baseSort }; + const sameSort = { ...baseSort }; + + const currentViewSorts: ViewSort[] = [existingSort]; + const newViewSorts: ViewSort[] = [sameSort]; + + const result = getViewSortsToUpdate(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); + + it('should handle empty arrays for both inputs', () => { + const currentViewSorts: ViewSort[] = []; + const newViewSorts: ViewSort[] = []; + + const result = getViewSortsToUpdate(currentViewSorts, newViewSorts); + + expect(result).toEqual([]); + }); +}); diff --git a/packages/twenty-front/src/modules/views/utils/areViewSortsEqual.ts b/packages/twenty-front/src/modules/views/utils/areViewSortsEqual.ts new file mode 100644 index 000000000..d028c2375 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/areViewSortsEqual.ts @@ -0,0 +1,12 @@ +import { ViewSort } from '@/views/types/ViewSort'; + +export const areViewSortsEqual = (viewSortA: ViewSort, viewSortB: ViewSort) => { + const propertiesToCompare: (keyof ViewSort)[] = [ + 'fieldMetadataId', + 'direction', + ]; + + return propertiesToCompare.every( + (property) => viewSortA[property] === viewSortB[property], + ); +}; diff --git a/packages/twenty-front/src/modules/views/utils/getViewSortsToCreate.ts b/packages/twenty-front/src/modules/views/utils/getViewSortsToCreate.ts new file mode 100644 index 000000000..72b14e70b --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/getViewSortsToCreate.ts @@ -0,0 +1,18 @@ +import { ViewSort } from '@/views/types/ViewSort'; +import { isDefined } from 'twenty-shared'; + +export const getViewSortsToCreate = ( + currentViewSorts: ViewSort[], + newViewSorts: ViewSort[], +) => { + return newViewSorts.filter((newViewSort) => { + const correspondingViewSort = currentViewSorts.find( + (currentViewSort) => + currentViewSort.fieldMetadataId === newViewSort.fieldMetadataId, + ); + + const shouldCreateBecauseViewSortIsNew = !isDefined(correspondingViewSort); + + return shouldCreateBecauseViewSortIsNew; + }); +}; diff --git a/packages/twenty-front/src/modules/views/utils/getViewSortsToDelete.ts b/packages/twenty-front/src/modules/views/utils/getViewSortsToDelete.ts new file mode 100644 index 000000000..778b53c0f --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/getViewSortsToDelete.ts @@ -0,0 +1,14 @@ +import { ViewSort } from '@/views/types/ViewSort'; + +export const getViewSortsToDelete = ( + currentViewSorts: ViewSort[], + newViewSorts: ViewSort[], +) => { + return currentViewSorts.filter( + (currentViewSort) => + !newViewSorts.some( + (newViewSort) => + newViewSort.fieldMetadataId === currentViewSort.fieldMetadataId, + ), + ); +}; diff --git a/packages/twenty-front/src/modules/views/utils/getViewSortsToUpdate.ts b/packages/twenty-front/src/modules/views/utils/getViewSortsToUpdate.ts new file mode 100644 index 000000000..1d9076698 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/getViewSortsToUpdate.ts @@ -0,0 +1,26 @@ +import { ViewSort } from '@/views/types/ViewSort'; +import { areViewSortsEqual } from '@/views/utils/areViewSortsEqual'; +import { isDefined } from 'twenty-shared'; + +export const getViewSortsToUpdate = ( + currentViewSorts: ViewSort[], + newViewSorts: ViewSort[], +) => { + return newViewSorts.filter((newViewSort) => { + const correspondingViewSort = currentViewSorts.find( + (currentViewSort) => + currentViewSort.fieldMetadataId === newViewSort.fieldMetadataId, + ); + + if (!isDefined(correspondingViewSort)) { + return false; + } + + const shouldUpdateBecauseViewSortIsDifferent = !areViewSortsEqual( + newViewSort, + correspondingViewSort, + ); + + return shouldUpdateBecauseViewSortIsDifferent; + }); +}; diff --git a/packages/twenty-front/src/modules/views/utils/mapRecordSortToViewSort.ts b/packages/twenty-front/src/modules/views/utils/mapRecordSortToViewSort.ts new file mode 100644 index 000000000..1d84ecfe8 --- /dev/null +++ b/packages/twenty-front/src/modules/views/utils/mapRecordSortToViewSort.ts @@ -0,0 +1,9 @@ +import { RecordSort } from '@/object-record/record-sort/types/RecordSort'; +import { ViewSort } from '@/views/types/ViewSort'; + +export const mapRecordSortToViewSort = (recordSort: RecordSort): ViewSort => { + return { + __typename: 'ViewSort', + ...recordSort, + } satisfies ViewSort; +};