Migrate to a monorepo structure (#2909)

This commit is contained in:
Charles Bochet
2023-12-10 18:10:54 +01:00
committed by GitHub
parent a70a9281eb
commit 5bdca9de6c
2304 changed files with 37152 additions and 25869 deletions

View File

@ -0,0 +1,69 @@
import styled from '@emotion/styled';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
import { Avatar } from '@/users/components/Avatar';
import { useFavorites } from '../hooks/useFavorites';
const StyledContainer = styled(NavigationDrawerSection)`
overflow-x: auto;
width: 100%;
`;
export const Favorites = () => {
const { favorites, handleReorderFavorite } = useFavorites({
objectNamePlural: 'companies',
});
if (!favorites || favorites.length === 0) return <></>;
return (
<StyledContainer>
<NavigationDrawerSectionTitle label="Favorites" />
<DraggableList
onDragEnd={handleReorderFavorite}
draggableItems={
<>
{favorites.map((favorite, index) => {
const {
id,
labelIdentifier,
avatarUrl,
avatarType,
link,
recordId,
} = favorite;
return (
<DraggableItem
key={id}
draggableId={id}
index={index}
itemComponent={
<NavigationDrawerItem
key={id}
label={labelIdentifier}
Icon={() => (
<Avatar
colorId={recordId}
avatarUrl={avatarUrl}
type={avatarType}
placeholder={labelIdentifier}
/>
)}
to={link}
/>
}
/>
);
})}
</>
}
/>
</StyledContainer>
);
};

View File

@ -0,0 +1,225 @@
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 { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { PaginatedRecordTypeResults } from '@/object-record/types/PaginatedRecordTypeResults';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { favoritesState } from '../states/favoritesState';
export const useFavorites = ({
objectNamePlural,
}: {
objectNamePlural: string;
}) => {
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const [favorites, setFavorites] = useRecoilState(favoritesState);
const {
updateOneRecordMutation: updateOneFavoriteMutation,
createOneRecordMutation: createOneFavoriteMutation,
deleteOneRecordMutation: deleteOneFavoriteMutation,
objectMetadataItem: favoriteObjectMetadataItem,
} = useObjectMetadataItem({
objectNameSingular: 'favorite',
});
const { registerOptimisticEffect, triggerOptimisticEffects } =
useOptimisticEffect({
objectNameSingular: 'favorite',
});
const { performOptimisticEvict } = useOptimisticEvict();
const { objectNameSingular } = useObjectNameSingularFromPlural({
objectNamePlural,
});
const { objectMetadataItem: favoriteTargetObjectMetadataItem } =
useObjectMetadataItem({
objectNameSingular,
});
const apolloClient = useApolloClient();
useFindManyRecords({
objectNameSingular: 'favorite',
onCompleted: useRecoilCallback(
({ snapshot, set }) =>
async (data: PaginatedRecordTypeResults<Required<Favorite>>) => {
const favorites = snapshot.getLoadable(favoritesState).getValue();
const queriedFavorites = mapFavorites(
data.edges.map((edge) => edge.node),
);
if (!isDeeplyEqual(favorites, queriedFavorites)) {
set(favoritesState, queriedFavorites);
}
if (!favoriteObjectMetadataItem) {
return;
}
registerOptimisticEffect({
variables: { filter: {}, orderBy: {} },
definition: getRecordOptimisticEffectDefinition({
objectMetadataItem: favoriteObjectMetadataItem,
}),
});
},
[favoriteObjectMetadataItem, registerOptimisticEffect],
),
});
const createFavorite = useRecoilCallback(
({ snapshot, set }) =>
async (favoriteTargetObjectId: string, additionalData?: any) => {
const favorites = snapshot.getLoadable(favoritesState).getValue();
if (!favoriteTargetObjectMetadataItem) {
return;
}
const targetObjectName = favoriteTargetObjectMetadataItem.nameSingular;
const result = await apolloClient.mutate({
mutation: createOneFavoriteMutation,
variables: {
input: {
[`${targetObjectName}Id`]: favoriteTargetObjectId,
position: favorites.length + 1,
workspaceMemberId: currentWorkspaceMember?.id,
},
},
});
triggerOptimisticEffects(`FavoriteEdge`, result.data[`createFavorite`]);
const createdFavorite = result?.data?.createFavorite;
const newFavorite = {
...additionalData,
...createdFavorite,
};
const newFavoritesMapped = mapFavorites([newFavorite]);
if (createdFavorite) {
set(favoritesState, [...favorites, ...newFavoritesMapped]);
}
},
[
apolloClient,
createOneFavoriteMutation,
currentWorkspaceMember?.id,
favoriteTargetObjectMetadataItem,
triggerOptimisticEffects,
],
);
const _updateFavoritePosition = useRecoilCallback(
({ snapshot, set }) =>
async (favoriteToUpdate: Favorite) => {
const favoritesStateFromSnapshot = snapshot.getLoadable(favoritesState);
const favorites = favoritesStateFromSnapshot.getValue();
const result = await apolloClient.mutate({
mutation: updateOneFavoriteMutation,
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, updateOneFavoriteMutation],
);
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: deleteOneFavoriteMutation,
variables: {
idToDelete: idToDelete,
},
});
performOptimisticEvict('Favorite', 'id', idToDelete ?? '');
set(
favoritesState,
favorites.filter((favorite: Favorite) => favorite.id !== idToDelete),
);
},
[apolloClient, deleteOneFavoriteMutation, performOptimisticEvict],
);
const computeNewPosition = (destIndex: number, sourceIndex: number) => {
if (destIndex === 0) {
return favorites[destIndex].position / 2;
}
if (destIndex === favorites.length - 1) {
return favorites[destIndex - 1].position + 1;
}
if (sourceIndex < destIndex) {
return (
(favorites[destIndex + 1].position + favorites[destIndex].position) / 2
);
}
return (
(favorites[destIndex - 1].position + favorites[destIndex].position) / 2
);
};
const handleReorderFavorite: OnDragEndResponder = (result) => {
if (!result.destination || !favorites) {
return;
}
const newPosition = computeNewPosition(
result.destination.index,
result.source.index,
);
const reorderFavorites = Array.from(favorites);
const [removed] = reorderFavorites.splice(result.source.index, 1);
const removedFav = { ...removed, position: newPosition };
reorderFavorites.splice(result.destination.index, 0, removedFav);
setFavorites(reorderFavorites);
_updateFavoritePosition(removedFav);
};
return {
favorites,
createFavorite,
deleteFavorite,
handleReorderFavorite,
};
};

View File

@ -0,0 +1,8 @@
import { atom } from 'recoil';
import { Favorite } from '@/favorites/types/Favorite';
export const favoritesState = atom<Favorite[]>({
key: 'favoritesState',
default: [],
});

View 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;
};

View File

@ -0,0 +1,38 @@
import { getLogoUrlFromDomainName } from '~/utils';
import { assertNotNull } from '~/utils/assert';
import { isDefined } from '~/utils/isDefined';
export const mapFavorites = (favorites: any) => {
return favorites
.map((favorite: any) => {
const recordInformation = isDefined(favorite?.person)
? {
id: favorite.person.id,
labelIdentifier:
favorite.person.name.firstName +
' ' +
favorite.person.name.lastName,
avatarUrl: favorite.person.avatarUrl,
avatarType: 'rounded',
link: `/object/person/${favorite.person.id}`,
}
: isDefined(favorite?.company)
? {
id: favorite.company.id,
labelIdentifier: favorite.company.name,
avatarUrl: getLogoUrlFromDomainName(favorite.company.domainName),
avatarType: 'squared',
link: `/object/company/${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);
};