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:
@ -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}
|
||||
/>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -26,7 +26,7 @@ export const EMPTY_MUTATION = gql`
|
||||
export const useObjectMetadataItem = ({
|
||||
objectNamePlural,
|
||||
objectNameSingular,
|
||||
}: ObjectMetadataItemIdentifier & { skip?: boolean }) => {
|
||||
}: ObjectMetadataItemIdentifier) => {
|
||||
const objectMetadataItem = useRecoilValue(
|
||||
objectMetadataItemFamilySelector({
|
||||
objectNamePlural,
|
||||
|
||||
@ -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={{
|
||||
|
||||
@ -54,7 +54,6 @@ export const useFindManyObjectRecords = <
|
||||
findManyQuery,
|
||||
} = useObjectMetadataItem({
|
||||
objectNamePlural,
|
||||
skip,
|
||||
});
|
||||
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
|
||||
@ -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,
|
||||
})) ?? [];
|
||||
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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({
|
||||
|
||||
Reference in New Issue
Block a user