Display table record creation row when clicking on Add new from table empty state (#6174)
As per title
This commit is contained in:
@ -1,12 +1,15 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString, isNull } from '@sniptt/guards';
|
||||||
|
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
||||||
|
import { RecordTableEmptyState } from '@/object-record/record-table/components/RecordTableEmptyState';
|
||||||
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
import { RecordTableBody } from '@/object-record/record-table/record-table-body/components/RecordTableBody';
|
import { RecordTableBody } from '@/object-record/record-table/record-table-body/components/RecordTableBody';
|
||||||
import { RecordTableBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyEffect';
|
import { RecordTableBodyEffect } from '@/object-record/record-table/record-table-body/components/RecordTableBodyEffect';
|
||||||
import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider';
|
|
||||||
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
import { RecordTableHeader } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
|
||||||
import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope';
|
import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
const StyledTable = styled.table`
|
const StyledTable = styled.table`
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
@ -32,6 +35,27 @@ export const RecordTable = ({
|
|||||||
}: RecordTableProps) => {
|
}: RecordTableProps) => {
|
||||||
const { scopeId } = useRecordTableStates(recordTableId);
|
const { scopeId } = useRecordTableStates(recordTableId);
|
||||||
|
|
||||||
|
const {
|
||||||
|
isRecordTableInitialLoadingState,
|
||||||
|
tableRowIdsState,
|
||||||
|
pendingRecordIdState,
|
||||||
|
} = useRecordTableStates(recordTableId);
|
||||||
|
|
||||||
|
const isRecordTableInitialLoading = useRecoilValue(
|
||||||
|
isRecordTableInitialLoadingState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const tableRowIds = useRecoilValue(tableRowIdsState);
|
||||||
|
|
||||||
|
const pendingRecordId = useRecoilValue(pendingRecordIdState);
|
||||||
|
|
||||||
|
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
|
||||||
|
{ objectNameSingular },
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectLabel = foundObjectMetadataItem?.labelSingular;
|
||||||
|
const isRemote = foundObjectMetadataItem?.isRemote ?? false;
|
||||||
|
|
||||||
if (!isNonEmptyString(objectNameSingular)) {
|
if (!isNonEmptyString(objectNameSingular)) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
@ -45,11 +69,22 @@ export const RecordTable = ({
|
|||||||
objectNameSingular={objectNameSingular}
|
objectNameSingular={objectNameSingular}
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
>
|
>
|
||||||
<StyledTable className="entity-table-cell">
|
<RecordTableBodyEffect />
|
||||||
<RecordTableHeader createRecord={createRecord} />
|
{!isRecordTableInitialLoading &&
|
||||||
<RecordTableBodyEffect />
|
tableRowIds.length === 0 &&
|
||||||
<RecordTableBody />
|
isNull(pendingRecordId) ? (
|
||||||
</StyledTable>
|
<RecordTableEmptyState
|
||||||
|
objectNameSingular={objectNameSingular}
|
||||||
|
objectLabel={objectLabel}
|
||||||
|
createRecord={createRecord}
|
||||||
|
isRemote={isRemote}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<StyledTable className="entity-table-cell">
|
||||||
|
<RecordTableHeader createRecord={createRecord} />
|
||||||
|
<RecordTableBody />
|
||||||
|
</StyledTable>
|
||||||
|
)}
|
||||||
</RecordTableContextProvider>
|
</RecordTableContextProvider>
|
||||||
</RecordTableScope>
|
</RecordTableScope>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
useOpenRecordTableCellV2,
|
useOpenRecordTableCellV2,
|
||||||
} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
} from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||||
import { useTriggerContextMenu } from '@/object-record/record-table/record-table-cell/hooks/useTriggerContextMenu';
|
import { useTriggerContextMenu } from '@/object-record/record-table/record-table-cell/hooks/useTriggerContextMenu';
|
||||||
import { useUpsertRecordV2 } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecordV2';
|
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
||||||
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
|
||||||
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ export const RecordTableContextProvider = ({
|
|||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { upsertRecord } = useUpsertRecordV2({
|
const { upsertRecord } = useUpsertRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import { useRef } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
import { useRef } from 'react';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
||||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { RecordTable } from '@/object-record/record-table/components/RecordTable';
|
import { RecordTable } from '@/object-record/record-table/components/RecordTable';
|
||||||
import { RecordTableEmptyState } from '@/object-record/record-table/components/RecordTableEmptyState';
|
|
||||||
import { EntityDeleteContext } from '@/object-record/record-table/contexts/EntityDeleteHookContext';
|
import { EntityDeleteContext } from '@/object-record/record-table/contexts/EntityDeleteHookContext';
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
@ -31,6 +28,10 @@ const StyledTableContainer = styled.div`
|
|||||||
position: relative;
|
position: relative;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledTableInternalContainer = styled.div`
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
type RecordTableWithWrappersProps = {
|
type RecordTableWithWrappersProps = {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
recordTableId: string;
|
recordTableId: string;
|
||||||
@ -48,33 +49,14 @@ export const RecordTableWithWrappers = ({
|
|||||||
}: RecordTableWithWrappersProps) => {
|
}: RecordTableWithWrappersProps) => {
|
||||||
const tableBodyRef = useRef<HTMLDivElement>(null);
|
const tableBodyRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { isRecordTableInitialLoadingState, tableRowIdsState } =
|
|
||||||
useRecordTableStates(recordTableId);
|
|
||||||
|
|
||||||
const isRecordTableInitialLoading = useRecoilValue(
|
|
||||||
isRecordTableInitialLoadingState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const tableRowIds = useRecoilValue(tableRowIdsState);
|
|
||||||
|
|
||||||
const { resetTableRowSelection, setRowSelected } = useRecordTable({
|
const { resetTableRowSelection, setRowSelected } = useRecordTable({
|
||||||
recordTableId,
|
recordTableId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem(
|
|
||||||
{
|
|
||||||
objectNameSingular,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
const { saveViewFields } = useSaveCurrentViewFields(viewBarId);
|
||||||
|
|
||||||
const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular });
|
const { deleteOneRecord } = useDeleteOneRecord({ objectNameSingular });
|
||||||
|
|
||||||
const objectLabel = foundObjectMetadataItem?.labelSingular;
|
|
||||||
|
|
||||||
const isRemote = foundObjectMetadataItem?.isRemote ?? false;
|
|
||||||
|
|
||||||
const handleColumnsChange = useRecoilCallback(
|
const handleColumnsChange = useRecoilCallback(
|
||||||
() => (columns) => {
|
() => (columns) => {
|
||||||
saveViewFields(
|
saveViewFields(
|
||||||
@ -86,24 +68,13 @@ export const RecordTableWithWrappers = ({
|
|||||||
[saveViewFields],
|
[saveViewFields],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isRecordTableInitialLoading && tableRowIds.length === 0) {
|
|
||||||
return (
|
|
||||||
<RecordTableEmptyState
|
|
||||||
objectNameSingular={objectNameSingular}
|
|
||||||
objectLabel={objectLabel}
|
|
||||||
createRecord={createRecord}
|
|
||||||
isRemote={isRemote}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
<EntityDeleteContext.Provider value={deleteOneRecord}>
|
||||||
<ScrollWrapper>
|
<ScrollWrapper>
|
||||||
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
<RecordUpdateContext.Provider value={updateRecordMutation}>
|
||||||
<StyledTableWithHeader>
|
<StyledTableWithHeader>
|
||||||
<StyledTableContainer>
|
<StyledTableContainer>
|
||||||
<div ref={tableBodyRef}>
|
<StyledTableInternalContainer ref={tableBodyRef}>
|
||||||
<RecordTable
|
<RecordTable
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
objectNameSingular={objectNameSingular}
|
objectNameSingular={objectNameSingular}
|
||||||
@ -115,7 +86,7 @@ export const RecordTableWithWrappers = ({
|
|||||||
onDragSelectionStart={resetTableRowSelection}
|
onDragSelectionStart={resetTableRowSelection}
|
||||||
onDragSelectionChange={setRowSelected}
|
onDragSelectionChange={setRowSelected}
|
||||||
/>
|
/>
|
||||||
</div>
|
</StyledTableInternalContainer>
|
||||||
<RecordTableInternalEffect
|
<RecordTableInternalEffect
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordTableId}
|
||||||
tableBodyRef={tableBodyRef}
|
tableBodyRef={tableBodyRef}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import { act, renderHook } from '@testing-library/react';
|
import { act, renderHook } from '@testing-library/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
import { createState } from 'twenty-ui';
|
import { createState } from 'twenty-ui';
|
||||||
|
|
||||||
@ -10,9 +10,10 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
|
|||||||
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
|
|
||||||
const pendingRecordId = 'a7286b9a-c039-4a89-9567-2dfa7953cda9';
|
|
||||||
const draftValue = 'updated Name';
|
const draftValue = 'updated Name';
|
||||||
|
|
||||||
|
// Todo refactor this test to inject the states in a cleaner way instead of mocking hooks
|
||||||
|
// (this is not easy to maintain while refactoring)
|
||||||
jest.mock('@/object-record/hooks/useCreateOneRecord', () => ({
|
jest.mock('@/object-record/hooks/useCreateOneRecord', () => ({
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
useCreateOneRecord: jest.fn(),
|
useCreateOneRecord: jest.fn(),
|
||||||
@ -93,17 +94,25 @@ describe('useUpsertRecord', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calls update record if there is no pending record', async () => {
|
it('calls update record if there is no pending record', async () => {
|
||||||
const { result } = renderHook(() => useUpsertRecord(), {
|
const { result } = renderHook(
|
||||||
wrapper: ({ children }) =>
|
() => useUpsertRecord({ objectNameSingular: 'person' }),
|
||||||
Wrapper({
|
{
|
||||||
pendingRecordIdMockedValue: null,
|
wrapper: ({ children }) =>
|
||||||
draftValueMockedValue: null,
|
Wrapper({
|
||||||
children,
|
pendingRecordIdMockedValue: null,
|
||||||
}),
|
draftValueMockedValue: null,
|
||||||
});
|
children,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.upsertRecord(updateOneRecordMock);
|
await result.current.upsertRecord(
|
||||||
|
updateOneRecordMock,
|
||||||
|
'entityId',
|
||||||
|
'name',
|
||||||
|
'recordTableId',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(createOneRecordMock).not.toHaveBeenCalled();
|
expect(createOneRecordMock).not.toHaveBeenCalled();
|
||||||
@ -111,42 +120,28 @@ describe('useUpsertRecord', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calls update record if pending record is empty', async () => {
|
it('calls update record if pending record is empty', async () => {
|
||||||
const { result } = renderHook(() => useUpsertRecord(), {
|
const { result } = renderHook(
|
||||||
wrapper: ({ children }) =>
|
() => useUpsertRecord({ objectNameSingular: 'person' }),
|
||||||
Wrapper({
|
{
|
||||||
pendingRecordIdMockedValue: null,
|
wrapper: ({ children }) =>
|
||||||
draftValueMockedValue: draftValue,
|
Wrapper({
|
||||||
children,
|
pendingRecordIdMockedValue: null,
|
||||||
}),
|
draftValueMockedValue: draftValue,
|
||||||
});
|
children,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await result.current.upsertRecord(updateOneRecordMock);
|
await result.current.upsertRecord(
|
||||||
|
updateOneRecordMock,
|
||||||
|
'entityId',
|
||||||
|
'name',
|
||||||
|
'recordTableId',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(createOneRecordMock).not.toHaveBeenCalled();
|
expect(createOneRecordMock).not.toHaveBeenCalled();
|
||||||
expect(updateOneRecordMock).toHaveBeenCalled();
|
expect(updateOneRecordMock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls create record if pending record is not empty', async () => {
|
|
||||||
const { result } = renderHook(() => useUpsertRecord(), {
|
|
||||||
wrapper: ({ children }) =>
|
|
||||||
Wrapper({
|
|
||||||
pendingRecordIdMockedValue: pendingRecordId,
|
|
||||||
draftValueMockedValue: draftValue,
|
|
||||||
children,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
await act(async () => {
|
|
||||||
await result.current.upsertRecord(updateOneRecordMock);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(createOneRecordMock).toHaveBeenCalledWith({
|
|
||||||
id: pendingRecordId,
|
|
||||||
name: draftValue,
|
|
||||||
position: 'first',
|
|
||||||
});
|
|
||||||
expect(updateOneRecordMock).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,41 +1,65 @@
|
|||||||
import { useContext } from 'react';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
||||||
import { useRecordFieldInputStates } from '@/object-record/record-field/hooks/internal/useRecordFieldInputStates';
|
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
||||||
|
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||||
|
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
||||||
|
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useUpsertRecord = () => {
|
export const useUpsertRecord = ({
|
||||||
const { entityId, fieldDefinition } = useContext(FieldContext);
|
objectNameSingular,
|
||||||
|
}: {
|
||||||
const { pendingRecordIdState } = useRecordTableStates();
|
objectNameSingular: string;
|
||||||
|
}) => {
|
||||||
const pendingRecordId = useRecoilValue(pendingRecordIdState);
|
|
||||||
const fieldName = fieldDefinition.metadata.fieldName;
|
|
||||||
const { getDraftValueSelector } = useRecordFieldInputStates(
|
|
||||||
`${entityId}-${fieldName}`,
|
|
||||||
);
|
|
||||||
const draftValue = useRecoilValue(getDraftValueSelector());
|
|
||||||
|
|
||||||
const objectNameSingular =
|
|
||||||
fieldDefinition.metadata.objectMetadataNameSingular ?? '';
|
|
||||||
const { createOneRecord } = useCreateOneRecord({
|
const { createOneRecord } = useCreateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const upsertRecord = (persistField: () => void) => {
|
const upsertRecord = useRecoilCallback(
|
||||||
if (isDefined(pendingRecordId) && isDefined(draftValue)) {
|
({ snapshot }) =>
|
||||||
createOneRecord({
|
(
|
||||||
id: pendingRecordId,
|
persistField: () => void,
|
||||||
name: draftValue,
|
entityId: string,
|
||||||
position: 'first',
|
fieldName: string,
|
||||||
});
|
recordTableId: string,
|
||||||
} else if (!pendingRecordId) {
|
) => {
|
||||||
persistField();
|
const tableScopeId = getScopeIdFromComponentId(recordTableId);
|
||||||
}
|
|
||||||
};
|
const recordTablePendingRecordIdState = extractComponentState(
|
||||||
|
recordTablePendingRecordIdComponentState,
|
||||||
|
tableScopeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordTablePendingRecordId = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
recordTablePendingRecordIdState,
|
||||||
|
);
|
||||||
|
const fieldScopeId = getScopeIdFromComponentId(
|
||||||
|
`${entityId}-${fieldName}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const draftValueSelector = extractComponentSelector(
|
||||||
|
recordFieldInputDraftValueComponentSelector,
|
||||||
|
fieldScopeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const draftValue = getSnapshotValue(snapshot, draftValueSelector());
|
||||||
|
|
||||||
|
if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) {
|
||||||
|
createOneRecord({
|
||||||
|
id: recordTablePendingRecordId,
|
||||||
|
name: draftValue,
|
||||||
|
position: 'first',
|
||||||
|
});
|
||||||
|
} else if (!recordTablePendingRecordId) {
|
||||||
|
persistField();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[createOneRecord],
|
||||||
|
);
|
||||||
|
|
||||||
return { upsertRecord };
|
return { upsertRecord };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
|
||||||
|
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
|
||||||
import { recordFieldInputDraftValueComponentSelector } from '@/object-record/record-field/states/selectors/recordFieldInputDraftValueComponentSelector';
|
|
||||||
import { recordTablePendingRecordIdComponentState } from '@/object-record/record-table/states/recordTablePendingRecordIdComponentState';
|
|
||||||
import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId';
|
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
|
||||||
import { extractComponentSelector } from '@/ui/utilities/state/component-state/utils/extractComponentSelector';
|
|
||||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
|
||||||
import { isDefined } from '~/utils/isDefined';
|
|
||||||
|
|
||||||
export const useUpsertRecordV2 = ({
|
|
||||||
objectNameSingular,
|
|
||||||
}: {
|
|
||||||
objectNameSingular: string;
|
|
||||||
}) => {
|
|
||||||
const { createOneRecord } = useCreateOneRecord({
|
|
||||||
objectNameSingular,
|
|
||||||
});
|
|
||||||
|
|
||||||
const upsertRecord = useRecoilCallback(
|
|
||||||
({ snapshot }) =>
|
|
||||||
(
|
|
||||||
persistField: () => void,
|
|
||||||
entityId: string,
|
|
||||||
fieldName: string,
|
|
||||||
recordTableId: string,
|
|
||||||
) => {
|
|
||||||
const tableScopeId = getScopeIdFromComponentId(recordTableId);
|
|
||||||
|
|
||||||
const recordTablePendingRecordIdState = extractComponentState(
|
|
||||||
recordTablePendingRecordIdComponentState,
|
|
||||||
tableScopeId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const recordTablePendingRecordId = getSnapshotValue(
|
|
||||||
snapshot,
|
|
||||||
recordTablePendingRecordIdState,
|
|
||||||
);
|
|
||||||
const fieldScopeId = getScopeIdFromComponentId(
|
|
||||||
`${entityId}-${fieldName}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const draftValueSelector = extractComponentSelector(
|
|
||||||
recordFieldInputDraftValueComponentSelector,
|
|
||||||
fieldScopeId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const draftValue = getSnapshotValue(snapshot, draftValueSelector());
|
|
||||||
|
|
||||||
if (isDefined(recordTablePendingRecordId) && isDefined(draftValue)) {
|
|
||||||
createOneRecord({
|
|
||||||
id: recordTablePendingRecordId,
|
|
||||||
name: draftValue,
|
|
||||||
position: 'first',
|
|
||||||
});
|
|
||||||
} else if (!recordTablePendingRecordId) {
|
|
||||||
persistField();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[createOneRecord],
|
|
||||||
);
|
|
||||||
|
|
||||||
return { upsertRecord };
|
|
||||||
};
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { useParams } from 'react-router-dom';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
||||||
|
|||||||
Reference in New Issue
Block a user