Update favorites query and state to work with new backend (#2520)
* wip * wip * adding favorite works in the database * favorites are showing in the left drawer * update favoorite NavItem link * wip * adding favorite works * everything seems to work * fix delete bug * fix update favorite position * update Favorite type * Fix --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -38,8 +38,7 @@ export const useAuth = () => {
|
|||||||
const [verify] = useVerifyMutation();
|
const [verify] = useVerifyMutation();
|
||||||
const [checkUserExistsQuery, { data: checkUserExistsData }] =
|
const [checkUserExistsQuery, { data: checkUserExistsData }] =
|
||||||
useCheckUserExistsLazyQuery();
|
useCheckUserExistsLazyQuery();
|
||||||
const [getCurrentWorkspaceQuery, { data: getCurrentWorkspaceData }] =
|
const [getCurrentWorkspaceQuery] = useGetCurrentWorkspaceLazyQuery();
|
||||||
useGetCurrentWorkspaceLazyQuery();
|
|
||||||
|
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
|
|
||||||
@ -185,7 +184,13 @@ export const useAuth = () => {
|
|||||||
|
|
||||||
return { user, workspaceMember, workspace };
|
return { user, workspaceMember, workspace };
|
||||||
},
|
},
|
||||||
[setIsVerifyPendingState, signUp, handleVerify, client],
|
[
|
||||||
|
setIsVerifyPendingState,
|
||||||
|
signUp,
|
||||||
|
handleVerify,
|
||||||
|
client,
|
||||||
|
setCurrentWorkspaceMember,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleGoogleLogin = useCallback((workspaceInviteHash?: string) => {
|
const handleGoogleLogin = useCallback((workspaceInviteHash?: string) => {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export const useCompanyTableContextMenuEntries = () => {
|
|||||||
|
|
||||||
const { data } = useGetFavoritesQuery();
|
const { data } = useGetFavoritesQuery();
|
||||||
const favorites = data?.findFavorites;
|
const favorites = data?.findFavorites;
|
||||||
const { insertCompanyFavorite, deleteCompanyFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites();
|
||||||
|
|
||||||
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
const selectedRowIds = snapshot
|
const selectedRowIds = snapshot
|
||||||
@ -53,8 +53,8 @@ export const useCompanyTableContextMenuEntries = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
resetTableRowSelection();
|
resetTableRowSelection();
|
||||||
if (isFavorite) deleteCompanyFavorite(selectedCompanyId);
|
if (isFavorite) deleteFavorite(selectedCompanyId);
|
||||||
else insertCompanyFavorite(selectedCompanyId);
|
else createFavorite('company', selectedCompanyId);
|
||||||
});
|
});
|
||||||
|
|
||||||
const [deleteManyCompany] = useDeleteManyCompaniesMutation({
|
const [deleteManyCompany] = useDeleteManyCompaniesMutation({
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { favoritesState } from '@/favorites/states/favoritesState';
|
||||||
|
import { mapFavorites } from '@/favorites/utils/mapFavorites';
|
||||||
|
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
||||||
|
import { PaginatedObjectTypeResults } from '@/object-record/types/PaginatedObjectTypeResults';
|
||||||
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
|
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
|
||||||
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
|
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
|
||||||
import NavItem from '@/ui/navigation/navbar/components/NavItem';
|
import NavItem from '@/ui/navigation/navbar/components/NavItem';
|
||||||
import NavTitle from '@/ui/navigation/navbar/components/NavTitle';
|
import NavTitle from '@/ui/navigation/navbar/components/NavTitle';
|
||||||
import { Avatar } from '@/users/components/Avatar';
|
import { Avatar } from '@/users/components/Avatar';
|
||||||
import { useGetFavoritesQuery } from '~/generated/graphql';
|
import { Company, Favorite } from '~/generated-metadata/graphql';
|
||||||
import { getLogoUrlFromDomainName } from '~/utils';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
import { useFavorites } from '../hooks/useFavorites';
|
import { useFavorites } from '../hooks/useFavorites';
|
||||||
import { favoritesState } from '../states/favoritesState';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -20,34 +24,73 @@ const StyledContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const Favorites = () => {
|
export const Favorites = () => {
|
||||||
const [favorites, setFavorites] = useRecoilState(favoritesState);
|
const { favorites, handleReorderFavorite } = useFavorites();
|
||||||
const { handleReorderFavorite } = useFavorites();
|
const [allCompanies, setAllCompanies] = useState<
|
||||||
|
Record<string, { name: string; domainName?: string }>
|
||||||
|
>({});
|
||||||
|
const [allPeople, setAllPeople] = useState<
|
||||||
|
Record<string, { firstName: string; lastName: string; avatarUrl?: string }>
|
||||||
|
>({});
|
||||||
|
|
||||||
useGetFavoritesQuery({
|
// This is only temporary and will be refactored once we have main identifiers
|
||||||
onCompleted: (data) =>
|
const { loading: companiesLoading } = useFindManyObjectRecords({
|
||||||
setFavorites(
|
objectNamePlural: 'companiesV2',
|
||||||
data?.findFavorites.map((favorite) => {
|
onCompleted: async (
|
||||||
return {
|
data: PaginatedObjectTypeResults<Required<Company>>,
|
||||||
id: favorite.id,
|
) => {
|
||||||
person: favorite.person
|
setAllCompanies(
|
||||||
? {
|
data.edges.reduce(
|
||||||
id: favorite.person.id,
|
(acc, { node: company }) => ({
|
||||||
firstName: favorite.person.firstName,
|
...acc,
|
||||||
lastName: favorite.person.lastName,
|
[company.id]: {
|
||||||
avatarUrl: favorite.person.avatarUrl,
|
name: company.name,
|
||||||
}
|
domainName: company.domainName,
|
||||||
: undefined,
|
},
|
||||||
company: favorite.company
|
}),
|
||||||
? {
|
{},
|
||||||
id: favorite.company.id,
|
),
|
||||||
name: favorite.company.name,
|
);
|
||||||
domainName: favorite.company.domainName,
|
},
|
||||||
}
|
});
|
||||||
: undefined,
|
|
||||||
position: favorite.position,
|
const { loading: peopleLoading } = useFindManyObjectRecords({
|
||||||
};
|
objectNamePlural: 'peopleV2',
|
||||||
}) ?? [],
|
onCompleted: async (data) => {
|
||||||
),
|
setAllPeople(
|
||||||
|
data.edges.reduce(
|
||||||
|
(acc, { node: person }) => ({
|
||||||
|
...acc,
|
||||||
|
[person.id]: {
|
||||||
|
firstName: person.firstName,
|
||||||
|
lastName: person.lastName,
|
||||||
|
avatarUrl: person.avatarUrl,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useFindManyObjectRecords({
|
||||||
|
skip: companiesLoading || peopleLoading,
|
||||||
|
objectNamePlural: 'favoritesV2',
|
||||||
|
onCompleted: useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (data: PaginatedObjectTypeResults<Required<Favorite>>) => {
|
||||||
|
const favoriteState = snapshot.getLoadable(favoritesState);
|
||||||
|
const favorites = favoriteState.getValue();
|
||||||
|
|
||||||
|
const queriedFavorites = mapFavorites(data.edges, {
|
||||||
|
...allCompanies,
|
||||||
|
...allPeople,
|
||||||
|
});
|
||||||
|
if (!isDeeplyEqual(favorites, queriedFavorites)) {
|
||||||
|
set(favoritesState, queriedFavorites);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[allCompanies, allPeople],
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!favorites || favorites.length === 0) return <></>;
|
if (!favorites || favorites.length === 0) return <></>;
|
||||||
@ -60,47 +103,28 @@ export const Favorites = () => {
|
|||||||
draggableItems={
|
draggableItems={
|
||||||
<>
|
<>
|
||||||
{favorites.map((favorite, index) => {
|
{favorites.map((favorite, index) => {
|
||||||
const { id, person, company } = favorite;
|
const { id, labelIdentifier, avatarUrl, avatarType, link } =
|
||||||
|
favorite;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableItem
|
<DraggableItem
|
||||||
key={id}
|
key={id}
|
||||||
draggableId={id}
|
draggableId={id}
|
||||||
index={index}
|
index={index}
|
||||||
itemComponent={
|
itemComponent={
|
||||||
<>
|
<NavItem
|
||||||
{person && (
|
key={id}
|
||||||
<NavItem
|
label={labelIdentifier}
|
||||||
key={id}
|
Icon={() => (
|
||||||
label={`${person.firstName} ${person.lastName}`}
|
<Avatar
|
||||||
Icon={() => (
|
colorId={id}
|
||||||
<Avatar
|
avatarUrl={avatarUrl}
|
||||||
colorId={person.id}
|
type={avatarType}
|
||||||
avatarUrl={person.avatarUrl ?? ''}
|
placeholder={labelIdentifier}
|
||||||
type="rounded"
|
|
||||||
placeholder={`${person.firstName} ${person.lastName}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
to={`/person/${person.id}`}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{company && (
|
to={link}
|
||||||
<NavItem
|
/>
|
||||||
key={id}
|
|
||||||
label={company.name}
|
|
||||||
Icon={() => (
|
|
||||||
<Avatar
|
|
||||||
avatarUrl={
|
|
||||||
getLogoUrlFromDomainName(company.domainName) ??
|
|
||||||
''
|
|
||||||
}
|
|
||||||
type="squared"
|
|
||||||
placeholder={company.name}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
to={`/companies/${company.id}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,108 +1,114 @@
|
|||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { useApolloClient } from '@apollo/client';
|
||||||
import { OnDragEndResponder } from '@hello-pangea/dnd';
|
import { OnDragEndResponder } from '@hello-pangea/dnd';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { GET_COMPANY } from '@/companies/graphql/queries/getCompany';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { GET_PERSON } from '@/people/graphql/queries/getPerson';
|
import { Favorite } from '@/favorites/types/Favorite';
|
||||||
import {
|
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
||||||
Favorite,
|
|
||||||
useDeleteFavoriteMutation,
|
|
||||||
useInsertCompanyFavoriteMutation,
|
|
||||||
useInsertPersonFavoriteMutation,
|
|
||||||
useUpdateOneFavoriteMutation,
|
|
||||||
} from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { GET_FAVORITES } from '../graphql/queries/getFavorites';
|
|
||||||
import { favoritesState } from '../states/favoritesState';
|
import { favoritesState } from '../states/favoritesState';
|
||||||
|
|
||||||
export const useFavorites = () => {
|
export const useFavorites = () => {
|
||||||
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
const [favorites, setFavorites] = useRecoilState(favoritesState);
|
const [favorites, setFavorites] = useRecoilState(favoritesState);
|
||||||
|
|
||||||
const [insertCompanyFavoriteMutation] = useInsertCompanyFavoriteMutation();
|
const { updateOneMutation, createOneMutation, deleteOneMutation } =
|
||||||
const [insertPersonFavoriteMutation] = useInsertPersonFavoriteMutation();
|
useFindOneObjectMetadataItem({
|
||||||
const [deleteFavoriteMutation] = useDeleteFavoriteMutation();
|
objectNameSingular: 'favoriteV2',
|
||||||
const [updateOneFavoritesMutation] = useUpdateOneFavoriteMutation();
|
|
||||||
|
|
||||||
const insertCompanyFavorite = (companyId: string) => {
|
|
||||||
insertCompanyFavoriteMutation({
|
|
||||||
variables: {
|
|
||||||
data: {
|
|
||||||
companyId,
|
|
||||||
position: favorites.length + 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [
|
|
||||||
getOperationName(GET_FAVORITES) ?? '',
|
|
||||||
getOperationName(GET_COMPANY) ?? '',
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const insertPersonFavorite = (personId: string) => {
|
const apolloClient = useApolloClient();
|
||||||
insertPersonFavoriteMutation({
|
|
||||||
variables: {
|
|
||||||
data: {
|
|
||||||
personId,
|
|
||||||
position: favorites.length + 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [
|
|
||||||
getOperationName(GET_FAVORITES) ?? '',
|
|
||||||
getOperationName(GET_PERSON) ?? '',
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateFavoritePosition = async (
|
const createFavorite = useRecoilCallback(
|
||||||
favorites: Pick<Favorite, 'id' | 'position'>,
|
({ snapshot, set }) =>
|
||||||
) => {
|
async (
|
||||||
await updateOneFavoritesMutation({
|
favoriteNameToCreate: string,
|
||||||
variables: {
|
favoriteIdToCreate: string,
|
||||||
data: {
|
additionalData?: any,
|
||||||
position: favorites?.position,
|
) => {
|
||||||
},
|
const favoritesStateFromSnapshot = snapshot.getLoadable(favoritesState);
|
||||||
where: {
|
const favorites = favoritesStateFromSnapshot.getValue();
|
||||||
id: favorites.id,
|
if (!favoriteNameToCreate || !favoriteIdToCreate) {
|
||||||
},
|
return;
|
||||||
},
|
}
|
||||||
refetchQueries: [
|
|
||||||
getOperationName(GET_FAVORITES) ?? '',
|
const result = await apolloClient.mutate({
|
||||||
getOperationName(GET_PERSON) ?? '',
|
mutation: createOneMutation,
|
||||||
getOperationName(GET_COMPANY) ?? '',
|
variables: {
|
||||||
],
|
input: {
|
||||||
});
|
[favoriteNameToCreate]: favoriteIdToCreate,
|
||||||
};
|
position: favorites.length + 1,
|
||||||
const deleteCompanyFavorite = (companyId: string) => {
|
workspaceMember: currentWorkspaceMember?.id,
|
||||||
deleteFavoriteMutation({
|
},
|
||||||
variables: {
|
|
||||||
where: {
|
|
||||||
companyId: {
|
|
||||||
equals: companyId,
|
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
},
|
|
||||||
refetchQueries: [
|
|
||||||
getOperationName(GET_FAVORITES) ?? '',
|
|
||||||
getOperationName(GET_COMPANY) ?? '',
|
|
||||||
],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const deletePersonFavorite = (personId: string) => {
|
const createdFavorite = result?.data?.createFavoriteV2;
|
||||||
deleteFavoriteMutation({
|
|
||||||
variables: {
|
const newFavorite = {
|
||||||
where: {
|
...additionalData,
|
||||||
personId: {
|
...createdFavorite[favoriteNameToCreate],
|
||||||
equals: personId,
|
};
|
||||||
},
|
|
||||||
},
|
if (createdFavorite) {
|
||||||
|
set(favoritesState, [...favorites, newFavorite]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
refetchQueries: [
|
[apolloClient, createOneMutation, currentWorkspaceMember?.id],
|
||||||
getOperationName(GET_FAVORITES) ?? '',
|
);
|
||||||
getOperationName(GET_PERSON) ?? '',
|
|
||||||
],
|
const _updateFavoritePosition = useRecoilCallback(
|
||||||
});
|
({ snapshot, set }) =>
|
||||||
};
|
async (favoriteToUpdate: Favorite) => {
|
||||||
|
const favoritesStateFromSnapshot = snapshot.getLoadable(favoritesState);
|
||||||
|
const favorites = favoritesStateFromSnapshot.getValue();
|
||||||
|
const result = await apolloClient.mutate({
|
||||||
|
mutation: updateOneMutation,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
position: favoriteToUpdate?.position,
|
||||||
|
},
|
||||||
|
idToUpdate: favoriteToUpdate?.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedFavorite = result?.data?.updateFavoriteV2;
|
||||||
|
if (updatedFavorite) {
|
||||||
|
set(
|
||||||
|
favoritesState,
|
||||||
|
favorites.map((favorite: Favorite) =>
|
||||||
|
favorite.id === updatedFavorite.id ? favoriteToUpdate : favorite,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[apolloClient, updateOneMutation],
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteFavorite = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async (favoriteIdToDelete: string) => {
|
||||||
|
const favoritesStateFromSnapshot = snapshot.getLoadable(favoritesState);
|
||||||
|
const favorites = favoritesStateFromSnapshot.getValue();
|
||||||
|
const idToDelete = favorites.find(
|
||||||
|
(favorite: Favorite) => favorite.recordId === favoriteIdToDelete,
|
||||||
|
)?.id;
|
||||||
|
|
||||||
|
await apolloClient.mutate({
|
||||||
|
mutation: deleteOneMutation,
|
||||||
|
variables: {
|
||||||
|
idToDelete: idToDelete,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
set(
|
||||||
|
favoritesState,
|
||||||
|
favorites.filter((favorite: Favorite) => favorite.id !== idToDelete),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[apolloClient, deleteOneMutation],
|
||||||
|
);
|
||||||
|
|
||||||
const computeNewPosition = (destIndex: number, sourceIndex: number) => {
|
const computeNewPosition = (destIndex: number, sourceIndex: number) => {
|
||||||
if (destIndex === 0) {
|
if (destIndex === 0) {
|
||||||
@ -138,13 +144,12 @@ export const useFavorites = () => {
|
|||||||
const removedFav = { ...removed, position: newPosition };
|
const removedFav = { ...removed, position: newPosition };
|
||||||
reorderFavorites.splice(result.destination.index, 0, removedFav);
|
reorderFavorites.splice(result.destination.index, 0, removedFav);
|
||||||
setFavorites(reorderFavorites);
|
setFavorites(reorderFavorites);
|
||||||
updateFavoritePosition(removedFav);
|
_updateFavoritePosition(removedFav);
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
insertCompanyFavorite,
|
favorites,
|
||||||
insertPersonFavorite,
|
createFavorite,
|
||||||
deleteCompanyFavorite,
|
deleteFavorite,
|
||||||
deletePersonFavorite,
|
|
||||||
handleReorderFavorite,
|
handleReorderFavorite,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,8 @@
|
|||||||
import { atom } from 'recoil';
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
import { Company, Favorite, Person } from '~/generated/graphql';
|
import { Favorite } from '@/favorites/types/Favorite';
|
||||||
|
|
||||||
export const favoritesState = atom<
|
export const favoritesState = atom<Favorite[]>({
|
||||||
Array<
|
|
||||||
Pick<Favorite, 'id' | 'position'> & {
|
|
||||||
company?: Pick<Company, 'id' | 'name' | 'domainName'>;
|
|
||||||
} & {
|
|
||||||
person?: Pick<Person, 'id' | 'firstName' | 'lastName' | 'avatarUrl'>;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>({
|
|
||||||
key: 'favoritesState',
|
key: 'favoritesState',
|
||||||
default: [],
|
default: [],
|
||||||
});
|
});
|
||||||
|
|||||||
12
front/src/modules/favorites/types/Favorite.ts
Normal file
12
front/src/modules/favorites/types/Favorite.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { AvatarType } from '@/users/components/Avatar';
|
||||||
|
|
||||||
|
export type Favorite = {
|
||||||
|
id: string;
|
||||||
|
position: number;
|
||||||
|
[key: string]: any;
|
||||||
|
labelIdentifier: string;
|
||||||
|
avatarUrl: string;
|
||||||
|
avatarType: AvatarType;
|
||||||
|
link: string;
|
||||||
|
recordId: string;
|
||||||
|
};
|
||||||
51
front/src/modules/favorites/utils/mapFavorites.ts
Normal file
51
front/src/modules/favorites/utils/mapFavorites.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Company, Person } from '~/generated/graphql';
|
||||||
|
import { getLogoUrlFromDomainName } from '~/utils';
|
||||||
|
import { assertNotNull } from '~/utils/assert';
|
||||||
|
|
||||||
|
export const mapFavorites = (
|
||||||
|
favorites: any,
|
||||||
|
recordsDict: {
|
||||||
|
[key: string]: {
|
||||||
|
firstName?: Person['firstName'];
|
||||||
|
lastName?: Person['lastName'];
|
||||||
|
avatarUrl?: Person['avatarUrl'];
|
||||||
|
name?: Company['name'];
|
||||||
|
domainName?: Company['domainName'];
|
||||||
|
};
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
return favorites
|
||||||
|
.map(({ node: favorite }: any) => {
|
||||||
|
const recordInformation = favorite.person
|
||||||
|
? {
|
||||||
|
id: favorite.person.id,
|
||||||
|
labelIdentifier:
|
||||||
|
recordsDict[favorite.person.id].firstName +
|
||||||
|
' ' +
|
||||||
|
recordsDict[favorite.person.id].lastName,
|
||||||
|
avatarUrl: recordsDict[favorite.person.id].avatarUrl,
|
||||||
|
avatarType: 'rounded',
|
||||||
|
link: `/object/personV2/${favorite.person.id}`,
|
||||||
|
}
|
||||||
|
: favorite.company
|
||||||
|
? {
|
||||||
|
id: favorite.company.id,
|
||||||
|
labelIdentifier: recordsDict[favorite.company.id].name,
|
||||||
|
avatarUrl: getLogoUrlFromDomainName(
|
||||||
|
recordsDict[favorite.company.id].domainName ?? '',
|
||||||
|
),
|
||||||
|
avatarType: 'squared',
|
||||||
|
link: `/object/companyV2/${favorite.company.id}`,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...recordInformation,
|
||||||
|
recordId: recordInformation?.id,
|
||||||
|
id: favorite.id,
|
||||||
|
position: favorite.position,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(assertNotNull)
|
||||||
|
.sort((a: any, b: any) => a.position - b.position);
|
||||||
|
};
|
||||||
@ -3,6 +3,7 @@ import { DateTime } from 'luxon';
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
||||||
|
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||||
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
||||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
||||||
@ -24,6 +25,7 @@ import { PropertyBox } from '@/ui/object/record-inline-cell/property-box/compone
|
|||||||
import { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope';
|
import { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope';
|
||||||
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
|
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||||
|
import { getLogoUrlFromDomainName } from '~/utils';
|
||||||
|
|
||||||
import { useFindOneObjectRecord } from '../hooks/useFindOneObjectRecord';
|
import { useFindOneObjectRecord } from '../hooks/useFindOneObjectRecord';
|
||||||
import { useUpdateOneObjectRecord } from '../hooks/useUpdateOneObjectRecord';
|
import { useUpdateOneObjectRecord } from '../hooks/useUpdateOneObjectRecord';
|
||||||
@ -34,6 +36,8 @@ export const RecordShowPage = () => {
|
|||||||
objectMetadataId: string;
|
objectMetadataId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const { favorites, createFavorite, deleteFavorite } = useFavorites();
|
||||||
|
|
||||||
const { icons } = useLazyLoadIcons();
|
const { icons } = useLazyLoadIcons();
|
||||||
|
|
||||||
const { foundObjectMetadataItem } = useFindOneObjectMetadataItem({
|
const { foundObjectMetadataItem } = useFindOneObjectMetadataItem({
|
||||||
@ -76,8 +80,38 @@ export const RecordShowPage = () => {
|
|||||||
return [updateEntity, { loading: false }];
|
return [updateEntity, { loading: false }];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isFavorite = objectNameSingular
|
||||||
|
? favorites.some((favorite) => favorite.recordId === object?.id)
|
||||||
|
: false;
|
||||||
|
|
||||||
const handleFavoriteButtonClick = async () => {
|
const handleFavoriteButtonClick = async () => {
|
||||||
//
|
if (!objectNameSingular || !object) return;
|
||||||
|
if (isFavorite) deleteFavorite(object?.id);
|
||||||
|
else {
|
||||||
|
const additionalData =
|
||||||
|
objectNameSingular === 'peopleV2'
|
||||||
|
? {
|
||||||
|
labelIdentifier: object.firstName + ' ' + object.lastName,
|
||||||
|
avatarUrl: object.avatarUrl,
|
||||||
|
avatarType: 'rounded',
|
||||||
|
link: `/object/personV2/${object.id}`,
|
||||||
|
recordId: object.id,
|
||||||
|
}
|
||||||
|
: objectNameSingular === 'companyV2'
|
||||||
|
? {
|
||||||
|
labelIdentifier: object.name,
|
||||||
|
avatarUrl: getLogoUrlFromDomainName(object.domainName ?? ''),
|
||||||
|
avatarType: 'squared',
|
||||||
|
link: `/object/companyV2/${object.id}`,
|
||||||
|
recordId: object.id,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
createFavorite(
|
||||||
|
objectNameSingular.replace('V2', ''),
|
||||||
|
object.id,
|
||||||
|
additionalData,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!object) return <></>;
|
if (!object) return <></>;
|
||||||
@ -91,7 +125,7 @@ export const RecordShowPage = () => {
|
|||||||
Icon={IconBuildingSkyscraper}
|
Icon={IconBuildingSkyscraper}
|
||||||
>
|
>
|
||||||
<PageFavoriteButton
|
<PageFavoriteButton
|
||||||
isFavorite={false}
|
isFavorite={isFavorite}
|
||||||
onClick={handleFavoriteButtonClick}
|
onClick={handleFavoriteButtonClick}
|
||||||
/>
|
/>
|
||||||
<ShowPageAddButton
|
<ShowPageAddButton
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export const usePersonTableContextMenuEntries = () => {
|
|||||||
|
|
||||||
const { data } = useGetFavoritesQuery();
|
const { data } = useGetFavoritesQuery();
|
||||||
const favorites = data?.findFavorites;
|
const favorites = data?.findFavorites;
|
||||||
const { insertPersonFavorite, deletePersonFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites();
|
||||||
|
|
||||||
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
const selectedRowIds = snapshot
|
const selectedRowIds = snapshot
|
||||||
@ -51,8 +51,8 @@ export const usePersonTableContextMenuEntries = () => {
|
|||||||
!!favorites?.find((favorite) => favorite.person?.id === selectedPersonId);
|
!!favorites?.find((favorite) => favorite.person?.id === selectedPersonId);
|
||||||
|
|
||||||
resetTableRowSelection();
|
resetTableRowSelection();
|
||||||
if (isFavorite) deletePersonFavorite(selectedPersonId);
|
if (isFavorite) deleteFavorite(selectedPersonId);
|
||||||
else insertPersonFavorite(selectedPersonId);
|
else createFavorite('person', selectedPersonId);
|
||||||
});
|
});
|
||||||
|
|
||||||
const [deleteManyPerson] = useDeleteManyPersonMutation({
|
const [deleteManyPerson] = useDeleteManyPersonMutation({
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
import { RelationFieldDisplay } from '@/ui/object/field/meta-types/display/components/RelationFieldDisplay';
|
||||||
|
|
||||||
import { FieldContext } from '../contexts/FieldContext';
|
import { FieldContext } from '../contexts/FieldContext';
|
||||||
import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisplay';
|
import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisplay';
|
||||||
import { DateFieldDisplay } from '../meta-types/display/components/DateFieldDisplay';
|
import { DateFieldDisplay } from '../meta-types/display/components/DateFieldDisplay';
|
||||||
@ -10,7 +12,6 @@ import { MoneyAmountV2FieldDisplay } from '../meta-types/display/components/Mone
|
|||||||
import { MoneyFieldDisplay } from '../meta-types/display/components/MoneyFieldDisplay';
|
import { MoneyFieldDisplay } from '../meta-types/display/components/MoneyFieldDisplay';
|
||||||
import { NumberFieldDisplay } from '../meta-types/display/components/NumberFieldDisplay';
|
import { NumberFieldDisplay } from '../meta-types/display/components/NumberFieldDisplay';
|
||||||
import { PhoneFieldDisplay } from '../meta-types/display/components/PhoneFieldDisplay';
|
import { PhoneFieldDisplay } from '../meta-types/display/components/PhoneFieldDisplay';
|
||||||
import { RelationFieldDisplay } from '../meta-types/display/components/RelationFieldDisplay';
|
|
||||||
import { TextFieldDisplay } from '../meta-types/display/components/TextFieldDisplay';
|
import { TextFieldDisplay } from '../meta-types/display/components/TextFieldDisplay';
|
||||||
import { URLFieldDisplay } from '../meta-types/display/components/URLFieldDisplay';
|
import { URLFieldDisplay } from '../meta-types/display/components/URLFieldDisplay';
|
||||||
import { URLV2FieldDisplay } from '../meta-types/display/components/URLV2FieldDisplay';
|
import { URLV2FieldDisplay } from '../meta-types/display/components/URLV2FieldDisplay';
|
||||||
|
|||||||
@ -32,7 +32,7 @@ import { companyShowFieldDefinitions } from './constants/companyShowFieldDefinit
|
|||||||
|
|
||||||
export const CompanyShow = () => {
|
export const CompanyShow = () => {
|
||||||
const companyId = useParams().companyId ?? '';
|
const companyId = useParams().companyId ?? '';
|
||||||
const { insertCompanyFavorite, deleteCompanyFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { data, loading } = useCompanyQuery(companyId);
|
const { data, loading } = useCompanyQuery(companyId);
|
||||||
const company = data?.findUniqueCompany;
|
const company = data?.findUniqueCompany;
|
||||||
@ -49,8 +49,8 @@ export const CompanyShow = () => {
|
|||||||
company.Favorite && company.Favorite?.length > 0 ? true : false;
|
company.Favorite && company.Favorite?.length > 0 ? true : false;
|
||||||
|
|
||||||
const handleFavoriteButtonClick = async () => {
|
const handleFavoriteButtonClick = async () => {
|
||||||
if (isFavorite) deleteCompanyFavorite(companyId);
|
if (isFavorite) deleteFavorite(companyId);
|
||||||
else insertCompanyFavorite(companyId);
|
else createFavorite('company', companyId);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -35,7 +35,7 @@ import { personShowFieldDefinition } from './constants/personShowFieldDefinition
|
|||||||
|
|
||||||
export const PersonShow = () => {
|
export const PersonShow = () => {
|
||||||
const personId = useParams().personId ?? '';
|
const personId = useParams().personId ?? '';
|
||||||
const { insertPersonFavorite, deletePersonFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { data, loading } = usePersonQuery(personId);
|
const { data, loading } = usePersonQuery(personId);
|
||||||
@ -68,8 +68,8 @@ export const PersonShow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleFavoriteButtonClick = async () => {
|
const handleFavoriteButtonClick = async () => {
|
||||||
if (isFavorite) deletePersonFavorite(personId);
|
if (isFavorite) deleteFavorite(person.id);
|
||||||
else insertPersonFavorite(personId);
|
else createFavorite('person', person.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export enum SeedFavoriteFieldMetadataIds {
|
|||||||
WorkspaceMember = '20202020-1138-4e93-bbff-917a68161abf',
|
WorkspaceMember = '20202020-1138-4e93-bbff-917a68161abf',
|
||||||
Person = '20202020-0876-4735-8974-ff4d51aafa07',
|
Person = '20202020-0876-4735-8974-ff4d51aafa07',
|
||||||
Company = '20202020-09e1-4384-ae3e-39e7956396fe',
|
Company = '20202020-09e1-4384-ae3e-39e7956396fe',
|
||||||
|
CompanyV2 = '20202020-09e1-4384-ae3e-39e7956396ff',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const seedFavoriteFieldMetadata = async (
|
export const seedFavoriteFieldMetadata = async (
|
||||||
@ -86,7 +87,7 @@ export const seedFavoriteFieldMetadata = async (
|
|||||||
},
|
},
|
||||||
description: 'Favorite person',
|
description: 'Favorite person',
|
||||||
icon: 'IconUser',
|
icon: 'IconUser',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: SeedFavoriteFieldMetadataIds.Company,
|
id: SeedFavoriteFieldMetadataIds.Company,
|
||||||
@ -102,7 +103,7 @@ export const seedFavoriteFieldMetadata = async (
|
|||||||
},
|
},
|
||||||
description: 'Favorite company',
|
description: 'Favorite company',
|
||||||
icon: 'IconBuildingSkyscraper',
|
icon: 'IconBuildingSkyscraper',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.execute();
|
.execute();
|
||||||
|
|||||||
@ -105,7 +105,7 @@ export const seedPersonFieldMetadata = async (
|
|||||||
isCustom: false,
|
isCustom: false,
|
||||||
workspaceId: SeedWorkspaceId,
|
workspaceId: SeedWorkspaceId,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: 'URL',
|
type: 'TEXT',
|
||||||
name: 'linkedinUrl',
|
name: 'linkedinUrl',
|
||||||
label: 'Linkedin',
|
label: 'Linkedin',
|
||||||
targetColumnMap: {
|
targetColumnMap: {
|
||||||
@ -121,7 +121,7 @@ export const seedPersonFieldMetadata = async (
|
|||||||
isCustom: false,
|
isCustom: false,
|
||||||
workspaceId: SeedWorkspaceId,
|
workspaceId: SeedWorkspaceId,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: 'URL',
|
type: 'TEXT',
|
||||||
name: 'xUrl',
|
name: 'xUrl',
|
||||||
label: 'X',
|
label: 'X',
|
||||||
targetColumnMap: {
|
targetColumnMap: {
|
||||||
|
|||||||
Reference in New Issue
Block a user