From 8f623ceb5cdc652934e4bcbdfa7ffc3262c1add5 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Wed, 22 Nov 2023 11:43:40 +0100 Subject: [PATCH] Fix bug favorite optimistic rendering and opportunity prefill (#2633) * Fix bug favorite optimistic rendering and opportunity prefill * Fixes --- .../favorites/components/Favorites.tsx | 1 - .../modules/favorites/hooks/useFavorites.ts | 47 ++++++++++++++--- .../components/RecordTablePage.tsx | 11 +++- .../views/components/ViewBarEffect.tsx | 5 +- .../standard-objects-prefill-data/view.ts | 17 +----- .../standard-objects/opportunity.ts | 52 +++++++++++++++++++ 6 files changed, 105 insertions(+), 28 deletions(-) diff --git a/front/src/modules/favorites/components/Favorites.tsx b/front/src/modules/favorites/components/Favorites.tsx index 86f8402f3..e66db6cb0 100644 --- a/front/src/modules/favorites/components/Favorites.tsx +++ b/front/src/modules/favorites/components/Favorites.tsx @@ -16,7 +16,6 @@ const StyledContainer = styled.div` `; export const Favorites = () => { - // This is only temporary and will be refactored once we have main identifiers const { favorites, handleReorderFavorite } = useFavorites({ objectNamePlural: 'companies', }); diff --git a/front/src/modules/favorites/hooks/useFavorites.ts b/front/src/modules/favorites/hooks/useFavorites.ts index 35baacffa..9ba3d1193 100644 --- a/front/src/modules/favorites/hooks/useFavorites.ts +++ b/front/src/modules/favorites/hooks/useFavorites.ts @@ -2,10 +2,13 @@ import { useApolloClient } from '@apollo/client'; import { OnDragEndResponder } from '@hello-pangea/dnd'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; +import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect'; +import { useOptimisticEvict } from '@/apollo/optimistic-effect/hooks/useOptimisticEvict'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { Favorite } from '@/favorites/types/Favorite'; import { mapFavorites } from '@/favorites/utils/mapFavorites'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition'; import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords'; import { PaginatedObjectTypeResults } from '@/object-record/types/PaginatedObjectTypeResults'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; @@ -21,10 +24,20 @@ export const useFavorites = ({ const [favorites, setFavorites] = useRecoilState(favoritesState); - const { updateOneMutation, createOneMutation, deleteOneMutation } = - useObjectMetadataItem({ - objectNamePlural: 'favorites', + const { + updateOneMutation, + createOneMutation, + deleteOneMutation, + objectMetadataItem: favoriteObjectMetadataItem, + } = useObjectMetadataItem({ + objectNamePlural: 'favorites', + }); + + const { registerOptimisticEffect, triggerOptimisticEffects } = + useOptimisticEffect({ + objectNameSingular: 'favorite', }); + const { performOptimisticEvict } = useOptimisticEvict(); const { objectMetadataItem: favoriteTargetObjectMetadataItem } = useObjectMetadataItem({ @@ -47,8 +60,19 @@ export const useFavorites = ({ if (!isDeeplyEqual(favorites, queriedFavorites)) { set(favoritesState, queriedFavorites); } + + if (!favoriteObjectMetadataItem) { + return; + } + + registerOptimisticEffect({ + variables: { filter: {}, orderBy: {} }, + definition: getRecordOptimisticEffectDefinition({ + objectMetadataItem: favoriteObjectMetadataItem, + }), + }); }, - [], + [favoriteObjectMetadataItem, registerOptimisticEffect], ), }); @@ -57,8 +81,10 @@ export const useFavorites = ({ async (favoriteTargetObjectId: string, additionalData?: any) => { const favorites = snapshot.getLoadable(favoritesState).getValue(); - const targetObjectName = - favoriteTargetObjectMetadataItem?.nameSingular ?? ''; + if (!favoriteTargetObjectMetadataItem) { + return; + } + const targetObjectName = favoriteTargetObjectMetadataItem.nameSingular; const result = await apolloClient.mutate({ mutation: createOneMutation, @@ -71,6 +97,8 @@ export const useFavorites = ({ }, }); + triggerOptimisticEffects(`FavoriteEdge`, result.data[`createFavorite`]); + const createdFavorite = result?.data?.createFavorite; const newFavorite = { @@ -87,8 +115,9 @@ export const useFavorites = ({ [ apolloClient, createOneMutation, - currentWorkspaceMember, - favoriteTargetObjectMetadataItem?.nameSingular, + currentWorkspaceMember?.id, + favoriteTargetObjectMetadataItem, + triggerOptimisticEffects, ], ); @@ -136,6 +165,8 @@ export const useFavorites = ({ }, }); + performOptimisticEvict('Favorite', 'id', idToDelete ?? ''); + set( favoritesState, favorites.filter((favorite: Favorite) => favorite.id !== idToDelete), diff --git a/front/src/modules/object-record/components/RecordTablePage.tsx b/front/src/modules/object-record/components/RecordTablePage.tsx index a7fbc47ca..cda26874f 100644 --- a/front/src/modules/object-record/components/RecordTablePage.tsx +++ b/front/src/modules/object-record/components/RecordTablePage.tsx @@ -2,6 +2,8 @@ import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; +import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus'; +import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; import { IconBuildingSkyscraper } from '@/ui/display/icon'; @@ -36,13 +38,18 @@ export const RecordTablePage = () => { objectNamePlural, }); + const onboardingStatus = useOnboardingStatus(); + const navigate = useNavigate(); useEffect(() => { - if (objectNotFoundInMetadata) { + if ( + objectNotFoundInMetadata && + onboardingStatus === OnboardingStatus.Completed + ) { navigate('/'); } - }, [objectNotFoundInMetadata, navigate]); + }, [objectNotFoundInMetadata, navigate, onboardingStatus]); const { createOneObject } = useCreateOneObjectRecord({ objectNameSingular: objectMetadataItem?.nameSingular, diff --git a/front/src/modules/views/components/ViewBarEffect.tsx b/front/src/modules/views/components/ViewBarEffect.tsx index bb2929aa3..fdf94eea3 100644 --- a/front/src/modules/views/components/ViewBarEffect.tsx +++ b/front/src/modules/views/components/ViewBarEffect.tsx @@ -58,7 +58,10 @@ export const ViewBarEffect = () => { data.edges .map((view) => view.node) .find((view) => view.id === currentViewIdFromUrl) ?? - data.edges[0].node; + data.edges[0]?.node ?? + null; + + if (!currentView) return; set(currentViewIdState, currentView.id); diff --git a/server/src/workspace/workspace-manager/standard-objects-prefill-data/view.ts b/server/src/workspace/workspace-manager/standard-objects-prefill-data/view.ts index c7918e1b5..3d1e16579 100644 --- a/server/src/workspace/workspace-manager/standard-objects-prefill-data/view.ts +++ b/server/src/workspace/workspace-manager/standard-objects-prefill-data/view.ts @@ -14,21 +14,6 @@ export const viewPrefillData = async ( .into(`${schemaName}.view`, ['name', 'objectMetadataId', 'type']) .orIgnore() .values([ - { - name: 'All companies', - objectMetadataId: 'company', - type: 'table', - }, - { - name: 'All people', - objectMetadataId: 'person', - type: 'table', - }, - { - name: 'All opportunities', - objectMetadataId: 'company', - type: 'kanban', - }, { name: 'All Companies', objectMetadataId: objectMetadataMap['company'].id, @@ -41,7 +26,7 @@ export const viewPrefillData = async ( }, { name: 'All Opportunities', - objectMetadataId: objectMetadataMap['company'].id, + objectMetadataId: objectMetadataMap['opportunity'].id, type: 'kanban', }, ]) diff --git a/server/src/workspace/workspace-manager/standard-objects/opportunity.ts b/server/src/workspace/workspace-manager/standard-objects/opportunity.ts index ae6b36dd9..432fcf4a7 100644 --- a/server/src/workspace/workspace-manager/standard-objects/opportunity.ts +++ b/server/src/workspace/workspace-manager/standard-objects/opportunity.ts @@ -104,6 +104,58 @@ const opportunityMetadata = { icon: 'IconBuildingSkyscraper', isNullable: true, }, + { + isCustom: false, + isActive: true, + type: FieldMetadataType.UUID, + name: 'companyId', + label: 'Company ID (foreign key)', + targetColumnMap: {}, + description: 'Foreign key for company', + icon: undefined, + isNullable: true, + isSystem: true, + defaultValue: undefined, + }, + { + isCustom: false, + isActive: true, + type: FieldMetadataType.UUID, + name: 'personId', + label: 'Person ID (foreign key)', + targetColumnMap: {}, + description: 'Foreign key for person', + icon: undefined, + isNullable: true, + isSystem: true, + defaultValue: undefined, + }, + { + isCustom: false, + isActive: true, + type: FieldMetadataType.UUID, + name: 'pointOfContactId', + label: 'Point of Contact ID (foreign key)', + targetColumnMap: {}, + description: 'Foreign key for point of contact', + icon: undefined, + isNullable: true, + isSystem: true, + defaultValue: undefined, + }, + { + isCustom: false, + isActive: true, + type: FieldMetadataType.UUID, + name: 'pipelineStepId', + label: 'Pipeline Step ID (foreign key)', + targetColumnMap: {}, + description: 'Foreign key for pipeline step', + icon: undefined, + isNullable: true, + isSystem: true, + defaultValue: undefined, + }, ], };