Fix/company team crud (#2614)

* Fixed basePathToShowPage

* Fixed company team list

* Fixed : create, update, delete and detach people from company.
This commit is contained in:
Lucas Bordeau
2023-11-21 12:24:20 +01:00
committed by GitHub
parent 6f4a952381
commit b13d84fcda
9 changed files with 163 additions and 92 deletions

View File

@ -1,8 +1,11 @@
import { useState } from 'react';
import { useMutation, useQuery } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled';
import { flip, offset, useFloating } from '@floating-ui/react';
import { v4 } from 'uuid';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { IconPlus } from '@/ui/display/icon';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
@ -62,23 +65,43 @@ export const AddPersonToCompany = ({
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
const handlePersonSelected =
(companyId: string) => async (newPerson: any | null) => {
if (newPerson) {
// await updatePerson({
// variables: {
// where: {
// id: newPerson.id,
// },
// data: {
// company: { connect: { id: companyId } },
// },
// },
// refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
// });
handleClosePicker();
}
};
// TODO: refactor with useObjectMetadataItem V2 with typed hooks
const { findManyQuery, updateOneMutation, createOneMutation } =
useObjectMetadataItem({
objectNameSingular: 'person',
});
const { data: peopleNotInCompany } = useQuery(findManyQuery, {
variables: {
filter: {
companyId: {
neq: companyId,
},
},
},
});
const [updatePerson] = useMutation(updateOneMutation);
const [createPerson] = useMutation(createOneMutation);
const handlePersonSelected = async ({
selectedPersonId,
companyId,
}: {
selectedPersonId: string;
companyId: string | null;
}) => {
await updatePerson({
variables: {
idToUpdate: selectedPersonId,
input: {
companyId: companyId,
},
},
refetchQueries: [getOperationName(findManyQuery) ?? ''],
});
handleClosePicker();
};
const handleClosePicker = () => {
if (isDropdownOpen) {
@ -88,31 +111,44 @@ export const AddPersonToCompany = ({
};
const handleOpenPicker = () => {
if (!isDropdownOpen) {
setIsDropdownOpen(true);
setHotkeyScopeAndMemorizePreviousScope(
RelationPickerHotkeyScope.RelationPicker,
);
}
// TODO: TEMPORARY - example to implement when the picker is back
handleCreatePerson({
firstValue: 'John',
secondValue: 'Doe',
});
// handlePersonSelected({
// companyId,
// selectedPersonId: peopleNotInCompany.people.edges[0].node.id,
// });
// if (!isDropdownOpen) {
// setIsDropdownOpen(true);
// setHotkeyScopeAndMemorizePreviousScope(
// RelationPickerHotkeyScope.RelationPicker,
// );
// }
};
const handleInputKeyDown = async ({
const handleCreatePerson = async ({
firstValue,
secondValue,
}: FieldDoubleText) => {
if (!firstValue && !secondValue) return;
const newPersonId = v4();
// await insertOnePerson({
// variables: {
// data: {
// company: { connect: { id: companyId } },
// id: newPersonId,
// firstName: firstValue,
// lastName: secondValue,
// },
// },
// refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
// });
await createPerson({
variables: {
input: {
companyId: companyId,
id: newPersonId,
name: {
firstName: firstValue,
lastName: secondValue,
},
},
},
refetchQueries: [getOperationName(findManyQuery) ?? ''],
});
setIsCreationDropdownOpen(false);
};
@ -136,7 +172,7 @@ export const AddPersonToCompany = ({
firstValuePlaceholder="First Name"
secondValuePlaceholder="Last Name"
onClickOutside={handleEscape}
onEnter={handleInputKeyDown}
onEnter={handleCreatePerson}
onEscape={handleEscape}
hotkeyScope={RelationPickerHotkeyScope.RelationPicker}
/>

View File

@ -1,8 +1,11 @@
import { useQuery } from '@apollo/client';
import styled from '@emotion/styled';
import { isNonEmptyArray } from '@sniptt/guards';
import { Company } from '@/companies/types/Company';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { mapPaginatedObjectsToObjects } from '@/object-record/utils/mapPaginatedObjectsToObjects';
import { PeopleCard } from '@/people/components/PeopleCard';
import { Person } from '@/people/types/Person';
import { AddPersonToCompany } from './AddPersonToCompany';
@ -43,37 +46,44 @@ const StyledTitle = styled.div`
line-height: ${({ theme }) => theme.text.lineHeight.lg};
`;
export const CompanyTeam = ({ company }: CompanyTeamProps) => {
// const { data } = useGetPeopleQuery({
// variables: {
// orderBy: [],
// where: {
// companyId: {
// equals: company.id,
// },
// },
// },
// });
const data = {
people: [],
};
export const CompanyTeam = ({ company }: { company: any }) => {
const { findManyQuery } = useObjectMetadataItem({
objectNameSingular: 'person',
});
const peopleIds = data?.people?.map(({ id }) => id);
const { data } = useQuery(findManyQuery, {
variables: {
filter: {
companyId: {
eq: company.id,
},
},
},
});
const people = mapPaginatedObjectsToObjects({
objectNamePlural: 'people',
pagedObjects: data ?? [],
});
const peopleIds = people.map((person) => person.id);
const hasPeople = isNonEmptyArray(peopleIds);
return (
<>
{Boolean(data?.people?.length) && (
{hasPeople && (
<StyledContainer>
<StyledTitleContainer>
<StyledTitle>Team</StyledTitle>
<AddPersonToCompany companyId={company.id} peopleIds={peopleIds} />
</StyledTitleContainer>
<StyledListContainer>
{data?.people?.map((person: Person, id) => (
{people.map((person: any) => (
<PeopleCard
key={person.id}
person={person}
hasBottomBorder={id !== data.people.length - 1}
hasBottomBorder={person.id !== people.length - 1}
/>
))}
</StyledListContainer>

View File

@ -26,7 +26,7 @@ export const EMPTY_MUTATION = gql`
export const useObjectMetadataItem = ({
objectNamePlural,
objectNameSingular,
}: ObjectMetadataItemIdentifier & { skip?: boolean }) => {
}: ObjectMetadataItemIdentifier) => {
const objectMetadataItem = useRecoilValue(
objectMetadataItemFamilySelector({
objectNamePlural,

View File

@ -2,6 +2,7 @@ import { useParams } from 'react-router-dom';
import { DateTime } from 'luxon';
import { useRecoilState } from 'recoil';
import { CompanyTeam } from '@/companies/components/CompanyTeam';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
@ -35,14 +36,12 @@ export const RecordShowPage = () => {
objectMetadataId: string;
}>();
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
{
objectNameSingular,
},
);
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
const { favorites, createFavorite, deleteFavorite } = useFavorites({
objectNamePlural: foundObjectMetadataItem?.namePlural,
objectNamePlural: objectMetadataItem?.namePlural,
});
const [, setEntityFields] = useRecoilState(
@ -152,8 +151,8 @@ export const RecordShowPage = () => {
avatarType="squared"
/>
<PropertyBox extraPadding={true}>
{foundObjectMetadataItem &&
[...foundObjectMetadataItem.fields]
{objectMetadataItem &&
[...objectMetadataItem.fields]
.sort((a, b) =>
DateTime.fromISO(a.createdAt)
.diff(DateTime.fromISO(b.createdAt))
@ -182,6 +181,13 @@ export const RecordShowPage = () => {
);
})}
</PropertyBox>
{objectNameSingular === 'company' ? (
<>
<CompanyTeam company={object} />
</>
) : (
<></>
)}
</ShowPageLeftContainer>
<ShowPageRightContainer
entity={{

View File

@ -54,7 +54,6 @@ export const useFindManyObjectRecords = <
findManyQuery,
} = useObjectMetadataItem({
objectNamePlural,
skip,
});
const { enqueueSnackBar } = useSnackBar();

View File

@ -16,7 +16,7 @@ export const mapPaginatedObjectsToObjects = <
objectNamePlural: string;
}) => {
const formattedObjects: ObjectType[] =
pagedObjects?.[objectNamePlural].edges.map((objectEdge: ObjectEdge) => ({
pagedObjects?.[objectNamePlural]?.edges?.map((objectEdge: ObjectEdge) => ({
...objectEdge.node,
})) ?? [];

View File

@ -1,8 +1,11 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled';
import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { Person } from '@/people/types/Person';
import { IconDotsVertical, IconLinkOff, IconTrash } from '@/ui/display/icon';
import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton';
@ -104,29 +107,34 @@ export const PeopleCard = ({
setIsOptionsOpen(!isOptionsOpen);
};
const handleDetachPerson = () => {
// updatePerson({
// variables: {
// where: {
// id: person.id,
// },
// data: {
// company: {
// disconnect: true,
// },
// },
// },
// refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
// });
// TODO: refactor with useObjectMetadataItem V2 with typed hooks
const { findManyQuery, updateOneMutation, deleteOneMutation } =
useObjectMetadataItem({
objectNameSingular: 'person',
});
const [updatePerson] = useMutation(updateOneMutation);
const [deletePerson] = useMutation(deleteOneMutation);
const handleDetachPerson = async () => {
await updatePerson({
variables: {
idToUpdate: person.id,
input: {
companyId: null,
},
},
refetchQueries: [getOperationName(findManyQuery) ?? ''],
});
};
const handleDeletePerson = () => {
// deletePerson({
// variables: {
// ids: person.id,
// },
// refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
// });
deletePerson({
variables: {
idToDelete: person.id,
},
refetchQueries: [getOperationName(findManyQuery) ?? ''],
});
};
return (

View File

@ -23,7 +23,7 @@ export type MenuItemProps = {
isTooltipOpen?: boolean;
className?: string;
testId?: string;
onClick?: () => void;
onClick?: (event: MouseEvent<HTMLLIElement>) => void;
};
export const MenuItem = ({
@ -38,10 +38,17 @@ export const MenuItem = ({
}: MenuItemProps) => {
const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0;
const handleMenuItemClick = (event: MouseEvent<HTMLLIElement>) => {
event.preventDefault();
event.stopPropagation();
onClick?.(event);
};
return (
<StyledHoverableMenuItemBase
data-testid={testId ?? undefined}
onClick={onClick}
onClick={handleMenuItemClick}
className={className}
accent={accent}
isMenuOpen={!!isTooltipOpen}

View File

@ -1,11 +1,12 @@
import { useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { useRecoilState, useRecoilValue } from 'recoil';
import { FieldContext } from '@/ui/object/field/contexts/FieldContext';
import { useIsFieldEmpty } from '@/ui/object/field/hooks/useIsFieldEmpty';
import { entityFieldInitialValueFamilyState } from '@/ui/object/field/states/entityFieldInitialValueFamilyState';
import { FieldInitialValue } from '@/ui/object/field/types/FieldInitialValue';
import { useRecordTableScopedStates } from '@/ui/object/record-table/hooks/internal/useRecordTableScopedStates';
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@ -22,8 +23,13 @@ const DEFAULT_CELL_SCOPE: HotkeyScope = {
};
export const useTableCell = () => {
const { setCurrentTableCellInEditMode } = useCurrentTableCellEditMode();
const { objectMetadataConfigState } = useRecordTableScopedStates();
const objectMetadataConfig = useRecoilValue(objectMetadataConfigState);
const basePathToShowPage = objectMetadataConfig?.basePathToShowPage;
const { setCurrentTableCellInEditMode } = useCurrentTableCellEditMode();
const setHotkeyScope = useSetHotkeyScope();
const { setDragSelectionStartEnabled } = useDragSelect();
@ -37,8 +43,7 @@ export const useTableCell = () => {
const isEmpty = useIsFieldEmpty();
const { entityId, fieldDefinition, basePathToShowPage } =
useContext(FieldContext);
const { entityId, fieldDefinition } = useContext(FieldContext);
const [, setFieldInitialValue] = useRecoilState(
entityFieldInitialValueFamilyState({