Fix context menu and favorites (#2564)
This commit is contained in:
@ -36,7 +36,9 @@ export const useCompanyTableContextMenuEntries = () => {
|
|||||||
|
|
||||||
const { data } = useGetFavoritesQuery();
|
const { data } = useGetFavoritesQuery();
|
||||||
const favorites = data?.findFavorites;
|
const favorites = data?.findFavorites;
|
||||||
const { createFavorite, deleteFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites({
|
||||||
|
objectNamePlural: 'companies',
|
||||||
|
});
|
||||||
|
|
||||||
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
const selectedRowIds = snapshot
|
const selectedRowIds = snapshot
|
||||||
|
|||||||
@ -24,7 +24,10 @@ const StyledContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const Favorites = () => {
|
export const Favorites = () => {
|
||||||
const { favorites, handleReorderFavorite } = useFavorites();
|
// This is only temporary and will be refactored once we have main identifiers
|
||||||
|
const { favorites, handleReorderFavorite } = useFavorites({
|
||||||
|
objectNamePlural: 'companiesV2',
|
||||||
|
});
|
||||||
const [allCompanies, setAllCompanies] = useState<
|
const [allCompanies, setAllCompanies] = useState<
|
||||||
Record<string, { name: string; domainName?: string }>
|
Record<string, { name: string; domainName?: string }>
|
||||||
>({});
|
>({});
|
||||||
|
|||||||
@ -8,38 +8,45 @@ import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOne
|
|||||||
|
|
||||||
import { favoritesState } from '../states/favoritesState';
|
import { favoritesState } from '../states/favoritesState';
|
||||||
|
|
||||||
export const useFavorites = () => {
|
export const useFavorites = ({
|
||||||
|
objectNamePlural,
|
||||||
|
}: {
|
||||||
|
objectNamePlural: string | undefined;
|
||||||
|
}) => {
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
const [favorites, setFavorites] = useRecoilState(favoritesState);
|
const [favorites, setFavorites] = useRecoilState(favoritesState);
|
||||||
|
|
||||||
const { updateOneMutation, createOneMutation, deleteOneMutation } =
|
const { updateOneMutation, createOneMutation, deleteOneMutation } =
|
||||||
useFindOneObjectMetadataItem({
|
useFindOneObjectMetadataItem({
|
||||||
objectNameSingular: 'favoriteV2',
|
objectNamePlural: 'favoritesV2',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { foundObjectMetadataItem: favoriteTargetObjectMetadataItem } =
|
||||||
|
useFindOneObjectMetadataItem({
|
||||||
|
objectNamePlural,
|
||||||
});
|
});
|
||||||
|
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
const createFavorite = useRecoilCallback(
|
const createFavorite = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (
|
async (favoriteTargetObjectId: string, additionalData?: any) => {
|
||||||
favoriteNameToCreate: string,
|
|
||||||
favoriteIdToCreate: string,
|
|
||||||
additionalData?: any,
|
|
||||||
) => {
|
|
||||||
const favoritesStateFromSnapshot = snapshot.getLoadable(favoritesState);
|
const favoritesStateFromSnapshot = snapshot.getLoadable(favoritesState);
|
||||||
const favorites = favoritesStateFromSnapshot.getValue();
|
const favorites = favoritesStateFromSnapshot.getValue();
|
||||||
if (!favoriteNameToCreate || !favoriteIdToCreate) {
|
|
||||||
return;
|
const targetObjectName =
|
||||||
}
|
favoriteTargetObjectMetadataItem?.nameSingular.replace('V2', '') ??
|
||||||
|
'';
|
||||||
|
|
||||||
const result = await apolloClient.mutate({
|
const result = await apolloClient.mutate({
|
||||||
mutation: createOneMutation,
|
mutation: createOneMutation,
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
[favoriteNameToCreate]: favoriteIdToCreate,
|
[`${targetObjectName}Id`]: favoriteTargetObjectId,
|
||||||
position: favorites.length + 1,
|
position: favorites.length + 1,
|
||||||
workspaceMember: currentWorkspaceMember?.id,
|
// workspaceMember: currentWorkspaceMember?.id,
|
||||||
|
workspaceMemberId: currentWorkspaceMember?.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -48,14 +55,19 @@ export const useFavorites = () => {
|
|||||||
|
|
||||||
const newFavorite = {
|
const newFavorite = {
|
||||||
...additionalData,
|
...additionalData,
|
||||||
...createdFavorite[favoriteNameToCreate],
|
...createdFavorite[targetObjectName],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (createdFavorite) {
|
if (createdFavorite) {
|
||||||
set(favoritesState, [...favorites, newFavorite]);
|
set(favoritesState, [...favorites, newFavorite]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[apolloClient, createOneMutation, currentWorkspaceMember?.id],
|
[
|
||||||
|
apolloClient,
|
||||||
|
createOneMutation,
|
||||||
|
currentWorkspaceMember?.id,
|
||||||
|
favoriteTargetObjectMetadataItem,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const _updateFavoritePosition = useRecoilCallback(
|
const _updateFavoritePosition = useRecoilCallback(
|
||||||
|
|||||||
@ -36,14 +36,16 @@ export const RecordShowPage = () => {
|
|||||||
objectMetadataId: string;
|
objectMetadataId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { favorites, createFavorite, deleteFavorite } = useFavorites();
|
|
||||||
|
|
||||||
const { icons } = useLazyLoadIcons();
|
const { icons } = useLazyLoadIcons();
|
||||||
|
|
||||||
const { foundObjectMetadataItem } = useFindOneObjectMetadataItem({
|
const { foundObjectMetadataItem } = useFindOneObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { favorites, createFavorite, deleteFavorite } = useFavorites({
|
||||||
|
objectNamePlural: foundObjectMetadataItem?.namePlural,
|
||||||
|
});
|
||||||
|
|
||||||
const [, setEntityFields] = useRecoilState(
|
const [, setEntityFields] = useRecoilState(
|
||||||
entityFieldsFamilyState(objectMetadataId ?? ''),
|
entityFieldsFamilyState(objectMetadataId ?? ''),
|
||||||
);
|
);
|
||||||
@ -106,11 +108,7 @@ export const RecordShowPage = () => {
|
|||||||
recordId: object.id,
|
recordId: object.id,
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
createFavorite(
|
createFavorite(object.id, additionalData);
|
||||||
objectNameSingular.replace('V2', ''),
|
|
||||||
object.id,
|
|
||||||
additionalData,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
||||||
|
import { useRecordTableContextMenuEntries } from '@/object-record/hooks/useRecordTableContextMenuEntries';
|
||||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||||
import { useRecordTable } from '@/ui/object/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/ui/object/record-table/hooks/useRecordTable';
|
||||||
import { useView } from '@/views/hooks/useView';
|
import { useView } from '@/views/hooks/useView';
|
||||||
@ -56,5 +57,13 @@ export const RecordTableEffect = () => {
|
|||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const { setActionBarEntries, setContextMenuEntries } =
|
||||||
|
useRecordTableContextMenuEntries();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setActionBarEntries?.();
|
||||||
|
setContextMenuEntries?.();
|
||||||
|
}, [setActionBarEntries, setContextMenuEntries]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,133 @@
|
|||||||
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||||
|
import { useDeleteOneObjectRecord } from '@/object-record/hooks/useDeleteOneObjectRecord';
|
||||||
|
import {
|
||||||
|
IconCheckbox,
|
||||||
|
IconHeart,
|
||||||
|
IconHeartOff,
|
||||||
|
IconNotes,
|
||||||
|
IconTrash,
|
||||||
|
} from '@/ui/display/icon';
|
||||||
|
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
||||||
|
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
|
||||||
|
import { useRecordTable } from '@/ui/object/record-table/hooks/useRecordTable';
|
||||||
|
import { selectedRowIdsSelector } from '@/ui/object/record-table/states/selectors/selectedRowIdsSelector';
|
||||||
|
import { tableRowIdsState } from '@/ui/object/record-table/states/tableRowIdsState';
|
||||||
|
import { useGetFavoritesQuery } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const useRecordTableContextMenuEntries = () => {
|
||||||
|
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
||||||
|
const setActionBarEntriesState = useSetRecoilState(actionBarEntriesState);
|
||||||
|
|
||||||
|
const setTableRowIds = useSetRecoilState(tableRowIdsState);
|
||||||
|
|
||||||
|
const { scopeId: objectNamePlural, resetTableRowSelection } =
|
||||||
|
useRecordTable();
|
||||||
|
|
||||||
|
const { data } = useGetFavoritesQuery();
|
||||||
|
const favorites = data?.findFavorites;
|
||||||
|
|
||||||
|
const { createFavorite, deleteFavorite } = useFavorites({ objectNamePlural });
|
||||||
|
|
||||||
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
|
const selectedRowIds = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const selectedRowId = selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
||||||
|
|
||||||
|
const isFavorite =
|
||||||
|
!!selectedRowId &&
|
||||||
|
!!favorites?.find((favorite) => favorite.company?.id === selectedRowId);
|
||||||
|
|
||||||
|
resetTableRowSelection();
|
||||||
|
|
||||||
|
if (isFavorite) {
|
||||||
|
deleteFavorite(selectedRowId);
|
||||||
|
} else {
|
||||||
|
createFavorite(selectedRowId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { deleteOneObject } = useDeleteOneObjectRecord({
|
||||||
|
objectNamePlural,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDeleteClick = useRecoilCallback(({ snapshot }) => async () => {
|
||||||
|
const rowIdsToDelete = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
resetTableRowSelection();
|
||||||
|
|
||||||
|
if (deleteOneObject) {
|
||||||
|
for (const rowId of rowIdsToDelete) {
|
||||||
|
await deleteOneObject(rowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTableRowIds((tableRowIds) =>
|
||||||
|
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
setContextMenuEntries: useRecoilCallback(({ snapshot }) => () => {
|
||||||
|
const selectedRowIds = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const selectedRowId =
|
||||||
|
selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
||||||
|
|
||||||
|
const isFavorite =
|
||||||
|
!!selectedRowId &&
|
||||||
|
!!favorites?.find((favorite) => favorite.company?.id === selectedRowId);
|
||||||
|
|
||||||
|
setContextMenuEntries([
|
||||||
|
{
|
||||||
|
label: 'New task',
|
||||||
|
Icon: IconCheckbox,
|
||||||
|
onClick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'New note',
|
||||||
|
Icon: IconNotes,
|
||||||
|
onClick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: isFavorite ? 'Remove from favorites' : 'Add to favorites',
|
||||||
|
Icon: isFavorite ? IconHeartOff : IconHeart,
|
||||||
|
onClick: () => handleFavoriteButtonClick(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Delete',
|
||||||
|
Icon: IconTrash,
|
||||||
|
accent: 'danger',
|
||||||
|
onClick: () => handleDeleteClick(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}),
|
||||||
|
setActionBarEntries: useRecoilCallback(() => () => {
|
||||||
|
setActionBarEntriesState([
|
||||||
|
{
|
||||||
|
label: 'Task',
|
||||||
|
Icon: IconCheckbox,
|
||||||
|
onClick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Note',
|
||||||
|
Icon: IconNotes,
|
||||||
|
onClick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Delete',
|
||||||
|
Icon: IconTrash,
|
||||||
|
accent: 'danger',
|
||||||
|
onClick: () => handleDeleteClick(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -36,7 +36,9 @@ export const usePersonTableContextMenuEntries = () => {
|
|||||||
|
|
||||||
const { data } = useGetFavoritesQuery();
|
const { data } = useGetFavoritesQuery();
|
||||||
const favorites = data?.findFavorites;
|
const favorites = data?.findFavorites;
|
||||||
const { createFavorite, deleteFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites({
|
||||||
|
objectNamePlural: 'people',
|
||||||
|
});
|
||||||
|
|
||||||
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
const selectedRowIds = snapshot
|
const selectedRowIds = snapshot
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export type AvatarSize = 'xl' | 'lg' | 'md' | 'sm' | 'xs';
|
|||||||
export type AvatarProps = {
|
export type AvatarProps = {
|
||||||
avatarUrl: string | null | undefined;
|
avatarUrl: string | null | undefined;
|
||||||
size?: AvatarSize;
|
size?: AvatarSize;
|
||||||
placeholder: string;
|
placeholder: string | undefined;
|
||||||
colorId?: string;
|
colorId?: string;
|
||||||
type?: AvatarType;
|
type?: AvatarType;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
@ -118,11 +118,11 @@ export const Avatar = ({
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
size={size}
|
size={size}
|
||||||
type={type}
|
type={type}
|
||||||
colorId={colorId}
|
colorId={colorId ?? ''}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
{(noAvatarUrl || isInvalidAvatarUrl) &&
|
{(noAvatarUrl || isInvalidAvatarUrl) &&
|
||||||
placeholder[0]?.toLocaleUpperCase()}
|
placeholder?.[0]?.toLocaleUpperCase()}
|
||||||
</StyledAvatar>
|
</StyledAvatar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -31,7 +31,9 @@ import { companyShowFieldDefinitions } from './constants/companyShowFieldDefinit
|
|||||||
|
|
||||||
export const CompanyShow = () => {
|
export const CompanyShow = () => {
|
||||||
const companyId = useParams().companyId ?? '';
|
const companyId = useParams().companyId ?? '';
|
||||||
const { createFavorite, deleteFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites({
|
||||||
|
objectNamePlural: 'companies',
|
||||||
|
});
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { data, loading } = useCompanyQuery(companyId);
|
const { data, loading } = useCompanyQuery(companyId);
|
||||||
const company = data?.findUniqueCompany;
|
const company = data?.findUniqueCompany;
|
||||||
|
|||||||
@ -34,7 +34,9 @@ import { personShowFieldDefinition } from './constants/personShowFieldDefinition
|
|||||||
|
|
||||||
export const PersonShow = () => {
|
export const PersonShow = () => {
|
||||||
const personId = useParams().personId ?? '';
|
const personId = useParams().personId ?? '';
|
||||||
const { createFavorite, deleteFavorite } = useFavorites();
|
const { createFavorite, deleteFavorite } = useFavorites({
|
||||||
|
objectNamePlural: 'peopleV2',
|
||||||
|
});
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { data, loading } = usePersonQuery(personId);
|
const { data, loading } = usePersonQuery(personId);
|
||||||
|
|||||||
@ -125,11 +125,10 @@ export const seedCompanyFieldMetadata = async (
|
|||||||
},
|
},
|
||||||
description: 'The company name',
|
description: 'The company name',
|
||||||
icon: 'IconBuildingSkyscraper',
|
icon: 'IconBuildingSkyscraper',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: false,
|
isSystem: false,
|
||||||
defaultValue: { value: '' },
|
defaultValue: { value: '' },
|
||||||
},
|
},
|
||||||
|
|
||||||
// Scalar Fields
|
// Scalar Fields
|
||||||
{
|
{
|
||||||
id: SeedCompanyFieldMetadataIds.DomainName,
|
id: SeedCompanyFieldMetadataIds.DomainName,
|
||||||
|
|||||||
@ -135,7 +135,7 @@ export const seedFavoriteFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Favorite workspace member',
|
description: 'Favorite workspace member',
|
||||||
icon: 'IconCircleUser',
|
icon: 'IconCircleUser',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: false,
|
isSystem: false,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
@ -151,7 +151,7 @@ export const seedFavoriteFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Foreign key for workspace member',
|
description: 'Foreign key for workspace member',
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
@ -185,7 +185,7 @@ export const seedFavoriteFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Foreign key for person',
|
description: 'Foreign key for person',
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
@ -217,7 +217,7 @@ export const seedFavoriteFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Foreign key for company',
|
description: 'Foreign key for company',
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user