Added generic relation cell (#969)

* Added generic relation cell

* Deactivated debug

* Added default warning

* Put back display component

* Removed unused types
This commit is contained in:
Lucas Bordeau
2023-07-28 01:28:42 +02:00
committed by GitHub
parent 3b796ee68c
commit f4b8a3decb
21 changed files with 447 additions and 63 deletions

View File

@ -1,7 +1,7 @@
import { useContext } from 'react';
import { useSetRecoilState } from 'recoil';
import { GenericEditableCell } from '@/people/table/components/GenericEditableCell';
import { GenericEditableCell } from '@/ui/table/components/GenericEditableCell';
import { RecoilScope } from '../../recoil-scope/components/RecoilScope';
import { useCurrentRowSelected } from '../hooks/useCurrentRowSelected';

View File

@ -6,9 +6,8 @@ import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
import { useMapKeyboardToSoftFocus } from '../hooks/useMapKeyboardToSoftFocus';
import { EntityUpdateFieldHookContext } from '../states/EntityUpdateFieldHookContext';
import { EntityUpdateMutationHookContext } from '../states/EntityUpdateMutationHookContext';
import { TableHeader } from '../table-header/components/TableHeader';
import { EntityUpdateFieldHook } from '../types/CellUpdateFieldHook';
import { EntityTableBody } from './EntityTableBodyV2';
import { EntityTableHeader } from './EntityTableHeaderV2';
@ -90,7 +89,7 @@ type OwnProps<SortField> = {
availableSorts?: Array<SortType<SortField>>;
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
onRowSelectionChange?: (rowSelection: string[]) => void;
useUpdateField: EntityUpdateFieldHook;
useUpdateEntityMutation: any;
};
export function EntityTable<SortField>({
@ -98,7 +97,7 @@ export function EntityTable<SortField>({
viewIcon,
availableSorts,
onSortsUpdate,
useUpdateField,
useUpdateEntityMutation,
}: OwnProps<SortField>) {
const tableBodyRef = React.useRef<HTMLDivElement>(null);
@ -114,7 +113,7 @@ export function EntityTable<SortField>({
});
return (
<EntityUpdateFieldHookContext.Provider value={useUpdateField}>
<EntityUpdateMutationHookContext.Provider value={useUpdateEntityMutation}>
<StyledTableWithHeader>
<StyledTableContainer ref={tableBodyRef}>
<TableHeader
@ -131,6 +130,6 @@ export function EntityTable<SortField>({
</StyledTableWrapper>
</StyledTableContainer>
</StyledTableWithHeader>
</EntityUpdateFieldHookContext.Provider>
</EntityUpdateMutationHookContext.Provider>
);
}

View File

@ -0,0 +1,31 @@
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
import { GenericEditableRelationCell } from './GenericEditableRelationCell';
import { GenericEditableTextCell } from './GenericEditableTextCell';
type OwnProps = {
entityFieldMetadata: EntityFieldMetadata;
};
export function GenericEditableCell({ entityFieldMetadata }: OwnProps) {
switch (entityFieldMetadata.type) {
case 'text':
return (
<GenericEditableTextCell
fieldName={entityFieldMetadata.fieldName}
placeholder={entityFieldMetadata.label}
editModeHorizontalAlign="left"
/>
);
case 'relation': {
return (
<GenericEditableRelationCell fieldMetadata={entityFieldMetadata} />
);
}
default:
console.warn(
`Unknown field type: ${entityFieldMetadata.type} in GenericEditableCell`,
);
return <></>;
}
}

View File

@ -0,0 +1,35 @@
import { RelationPickerHotkeyScope } from '@/ui/relation-picker/types/RelationPickerHotkeyScope';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
import { GenericEditableRelationCellDisplayMode } from './GenericEditableRelationCellDisplayMode';
import { GenericEditableRelationCellEditMode } from './GenericEditableRelationCellEditMode';
type OwnProps = {
fieldMetadata: EntityFieldMetadata;
editModeHorizontalAlign?: 'left' | 'right';
placeholder?: string;
};
export function GenericEditableRelationCell({
fieldMetadata,
editModeHorizontalAlign,
placeholder,
}: OwnProps) {
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editHotkeyScope={{ scope: RelationPickerHotkeyScope.RelationPicker }}
editModeContent={
<GenericEditableRelationCellEditMode fieldMetadata={fieldMetadata} />
}
nonEditModeContent={
<GenericEditableRelationCellDisplayMode
fieldMetadata={fieldMetadata}
editModeHorizontalAlign={editModeHorizontalAlign}
placeholder={placeholder}
/>
}
></EditableCell>
);
}

View File

@ -0,0 +1,44 @@
import { useRecoilValue } from 'recoil';
import { CompanyChip } from '@/companies/components/CompanyChip';
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
import { getLogoUrlFromDomainName } from '~/utils';
type OwnProps = {
fieldMetadata: EntityFieldMetadata;
editModeHorizontalAlign?: 'left' | 'right';
placeholder?: string;
};
export function GenericEditableRelationCellDisplayMode({
fieldMetadata,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<any | null>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: fieldMetadata.fieldName,
}),
);
switch (fieldMetadata.relationType) {
case Entity.Company: {
return (
<CompanyChip
id={fieldValue?.id ?? ''}
name={fieldValue?.name ?? ''}
pictureUrl={getLogoUrlFromDomainName(fieldValue?.domainName)}
/>
);
}
default:
console.warn(
`Unknown relation type: "${fieldMetadata.relationType}" in GenericEditableRelationCellEditMode`,
);
return <> </>;
}
}

View File

@ -0,0 +1,68 @@
import { useRecoilState } from 'recoil';
import { CompanyPickerCell } from '@/companies/components/CompanyPickerCell';
import { useUpdateEntityField } from '@/people/hooks/useUpdateEntityField';
import { EntityForSelect } from '@/ui/relation-picker/types/EntityForSelect';
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
import { useEditableCell } from '@/ui/table/editable-cell/hooks/useEditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
type OwnProps = {
fieldMetadata: EntityFieldMetadata;
};
export function GenericEditableRelationCellEditMode({
fieldMetadata,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const { closeEditableCell } = useEditableCell();
const [fieldValueEntity] = useRecoilState<any | null>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: fieldMetadata.fieldName,
}),
);
const updateEntityField = useUpdateEntityField();
function handleEntitySubmit(newFieldEntity: EntityForSelect | null) {
if (
newFieldEntity?.id !== fieldValueEntity?.id &&
currentRowEntityId &&
updateEntityField
) {
updateEntityField(
currentRowEntityId,
fieldMetadata.fieldName,
newFieldEntity,
);
}
closeEditableCell();
}
function handleCancel() {
closeEditableCell();
}
switch (fieldMetadata.relationType) {
case Entity.Company: {
return (
<CompanyPickerCell
companyId={fieldValueEntity?.id ?? null}
onSubmit={handleEntitySubmit}
onCancel={handleCancel}
/>
);
}
default:
console.warn(
`Unknown relation type: "${fieldMetadata.relationType}" in GenericEditableRelationCellEditMode`,
);
return <></>;
}
}

View File

@ -0,0 +1,44 @@
import { useRecoilValue } from 'recoil';
import { InplaceInputTextDisplayMode } from '@/ui/display/component/InplaceInputTextDisplayMode';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import { GenericEditableTextCellEditMode } from './GenericEditableTextCellEditMode';
type OwnProps = {
fieldName: string;
editModeHorizontalAlign?: 'left' | 'right';
placeholder?: string;
};
export function GenericEditableTextCell({
fieldName,
editModeHorizontalAlign,
placeholder,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName,
}),
);
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<GenericEditableTextCellEditMode
fieldName={fieldName}
placeholder={placeholder}
/>
}
nonEditModeContent={
<InplaceInputTextDisplayMode>{fieldValue}</InplaceInputTextDisplayMode>
}
></EditableCell>
);
}

View File

@ -0,0 +1,46 @@
import { useRecoilState } from 'recoil';
import { useUpdateEntityField } from '@/people/hooks/useUpdateEntityField';
import { InplaceInputTextEditMode } from '@/ui/inplace-input/components/InplaceInputTextEditMode';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
type OwnProps = {
fieldName: string;
placeholder?: string;
};
export function GenericEditableTextCellEditMode({
fieldName,
placeholder,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
setFieldValue(newText);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, fieldName, newText);
}
}
return (
<InplaceInputTextEditMode
placeholder={placeholder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -1,7 +0,0 @@
import { useContext } from 'react';
import { EntityUpdateFieldHookContext } from '../states/EntityUpdateFieldHookContext';
export function useEntityUpdateFieldHook() {
return useContext(EntityUpdateFieldHookContext);
}

View File

@ -1,6 +0,0 @@
import { createContext } from 'react';
import { EntityUpdateFieldHook } from '../types/CellUpdateFieldHook';
export const EntityUpdateFieldHookContext =
createContext<EntityUpdateFieldHook | null>(null);

View File

@ -0,0 +1,3 @@
import { createContext } from 'react';
export const EntityUpdateMutationHookContext = createContext<any | null>(null);

View File

@ -1,10 +1,6 @@
export type EntityFieldType =
| 'text'
| 'number'
| 'date'
| 'select'
| 'checkbox'
| 'icon';
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
export type EntityFieldType = 'text' | 'relation';
export type EntityFieldMetadata = {
fieldName: string;
@ -13,4 +9,5 @@ export type EntityFieldMetadata = {
icon: JSX.Element;
columnSize: number;
filterIcon?: JSX.Element;
relationType?: Entity; // TODO: condition this type with type === "relation"
};