Board compact view and Company Picker for opportunity special case (#3713)
* Re-enabled board compact mode * Add specific case for opportunity to display company picker * Add infinite scroll * Remove useEffect * Fix * Fix
This commit is contained in:
@ -3,6 +3,8 @@ import { isFirstRecordBoardColumnFamilyStateScopeMap } from '@/object-record/rec
|
|||||||
import { isLastRecordBoardColumnFamilyStateScopeMap } from '@/object-record/record-board/states/isLastRecordBoardColumnFamilyStateScopeMap';
|
import { isLastRecordBoardColumnFamilyStateScopeMap } from '@/object-record/record-board/states/isLastRecordBoardColumnFamilyStateScopeMap';
|
||||||
import { isRecordBoardCardSelectedFamilyStateScopeMap } from '@/object-record/record-board/states/isRecordBoardCardSelectedFamilyStateScopeMap';
|
import { isRecordBoardCardSelectedFamilyStateScopeMap } from '@/object-record/record-board/states/isRecordBoardCardSelectedFamilyStateScopeMap';
|
||||||
import { isRecordBoardCompactModeActiveStateScopeMap } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveStateScopeMap';
|
import { isRecordBoardCompactModeActiveStateScopeMap } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveStateScopeMap';
|
||||||
|
import { isRecordBoardFetchingRecordsStateScopeMap } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsStateScopeMap';
|
||||||
|
import { onRecordBoardFetchMoreVisibilityChangeStateScopeMap } from '@/object-record/record-board/states/onRecordBoardFetchMoreVisibilityChangeStateScopeMap';
|
||||||
import { recordBoardColumnIdsStateScopeMap } from '@/object-record/record-board/states/recordBoardColumnIdsStateScopeMap';
|
import { recordBoardColumnIdsStateScopeMap } from '@/object-record/record-board/states/recordBoardColumnIdsStateScopeMap';
|
||||||
import { recordBoardFieldDefinitionsStateScopeMap } from '@/object-record/record-board/states/recordBoardFieldDefinitionsStateScopeMap';
|
import { recordBoardFieldDefinitionsStateScopeMap } from '@/object-record/record-board/states/recordBoardFieldDefinitionsStateScopeMap';
|
||||||
import { recordBoardFiltersStateScopeMap } from '@/object-record/record-board/states/recordBoardFiltersStateScopeMap';
|
import { recordBoardFiltersStateScopeMap } from '@/object-record/record-board/states/recordBoardFiltersStateScopeMap';
|
||||||
@ -30,6 +32,10 @@ export const useRecordBoardStates = (recordBoardId?: string) => {
|
|||||||
recordBoardObjectSingularNameStateScopeMap,
|
recordBoardObjectSingularNameStateScopeMap,
|
||||||
scopeId,
|
scopeId,
|
||||||
),
|
),
|
||||||
|
getIsFetchingRecordState: getState(
|
||||||
|
isRecordBoardFetchingRecordsStateScopeMap,
|
||||||
|
scopeId,
|
||||||
|
),
|
||||||
getColumnIdsState: getState(recordBoardColumnIdsStateScopeMap, scopeId),
|
getColumnIdsState: getState(recordBoardColumnIdsStateScopeMap, scopeId),
|
||||||
isFirstColumnFamilyState: getFamilyState(
|
isFirstColumnFamilyState: getFamilyState(
|
||||||
isFirstRecordBoardColumnFamilyStateScopeMap,
|
isFirstRecordBoardColumnFamilyStateScopeMap,
|
||||||
@ -72,5 +78,10 @@ export const useRecordBoardStates = (recordBoardId?: string) => {
|
|||||||
isRecordBoardCompactModeActiveStateScopeMap,
|
isRecordBoardCompactModeActiveStateScopeMap,
|
||||||
scopeId,
|
scopeId,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
getOnFetchMoreVisibilityChangeState: getState(
|
||||||
|
onRecordBoardFetchMoreVisibilityChangeStateScopeMap,
|
||||||
|
scopeId,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,6 +10,8 @@ export const useRecordBoard = (recordBoardId?: string) => {
|
|||||||
getFieldDefinitionsState,
|
getFieldDefinitionsState,
|
||||||
getObjectSingularNameState,
|
getObjectSingularNameState,
|
||||||
getSelectedRecordIdsSelector,
|
getSelectedRecordIdsSelector,
|
||||||
|
getIsCompactModeActiveState,
|
||||||
|
getOnFetchMoreVisibilityChangeState,
|
||||||
} = useRecordBoardStates(recordBoardId);
|
} = useRecordBoardStates(recordBoardId);
|
||||||
|
|
||||||
const { setColumns } = useSetRecordBoardColumns(recordBoardId);
|
const { setColumns } = useSetRecordBoardColumns(recordBoardId);
|
||||||
@ -24,5 +26,7 @@ export const useRecordBoard = (recordBoardId?: string) => {
|
|||||||
setFieldDefinitions,
|
setFieldDefinitions,
|
||||||
setObjectSingularName,
|
setObjectSingularName,
|
||||||
getSelectedRecordIdsSelector,
|
getSelectedRecordIdsSelector,
|
||||||
|
getIsCompactModeActiveState,
|
||||||
|
getOnFetchMoreVisibilityChangeState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { ReactNode, useContext, useState } from 'react';
|
import { ReactNode, useContext, useState } from 'react';
|
||||||
|
import { useInView } from 'react-intersection-observer';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ import { Checkbox, CheckboxVariant } from '@/ui/input/components/Checkbox';
|
|||||||
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
||||||
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||||
import { AnimatedEaseInOut } from '@/ui/utilities/animation/components/AnimatedEaseInOut';
|
import { AnimatedEaseInOut } from '@/ui/utilities/animation/components/AnimatedEaseInOut';
|
||||||
|
import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
|
|
||||||
const StyledBoardCard = styled.div<{ selected: boolean }>`
|
const StyledBoardCard = styled.div<{ selected: boolean }>`
|
||||||
background-color: ${({ theme, selected }) =>
|
background-color: ${({ theme, selected }) =>
|
||||||
@ -119,22 +121,26 @@ const StyledCompactIconContainer = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
margin-left: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledRecordInlineCellPlaceholder = styled.div`
|
||||||
|
height: 24px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordBoardCard = () => {
|
export const RecordBoardCard = () => {
|
||||||
const { recordId } = useContext(RecordBoardCardContext);
|
const { recordId } = useContext(RecordBoardCardContext);
|
||||||
const { updateOneRecord } = useContext(RecordBoardContext);
|
const { updateOneRecord, objectMetadataItem } =
|
||||||
|
useContext(RecordBoardContext);
|
||||||
const {
|
const {
|
||||||
getObjectSingularNameState,
|
|
||||||
getIsCompactModeActiveState,
|
getIsCompactModeActiveState,
|
||||||
isRecordBoardCardSelectedFamilyState,
|
isRecordBoardCardSelectedFamilyState,
|
||||||
getVisibleFieldDefinitionsState,
|
getVisibleFieldDefinitionsState,
|
||||||
} = useRecordBoardStates();
|
} = useRecordBoardStates();
|
||||||
|
|
||||||
const isCompactModeActive = useRecoilValue(getIsCompactModeActiveState());
|
const isCompactModeActive = useRecoilValue(getIsCompactModeActiveState());
|
||||||
const objectNameSingular = useRecoilValue(getObjectSingularNameState());
|
|
||||||
const [isCardInCompactMode, setIsCardInCompactMode] =
|
const [isCardInCompactMode, setIsCardInCompactMode] = useState(true);
|
||||||
useState(isCompactModeActive);
|
|
||||||
|
|
||||||
const [isCurrentCardSelected, setIsCurrentCardSelected] = useRecoilState(
|
const [isCurrentCardSelected, setIsCurrentCardSelected] = useRecoilState(
|
||||||
isRecordBoardCardSelectedFamilyState(recordId),
|
isRecordBoardCardSelectedFamilyState(recordId),
|
||||||
@ -190,13 +196,21 @@ export const RecordBoardCard = () => {
|
|||||||
return [updateEntity, { loading: false }];
|
return [updateEntity, { loading: false }];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!objectNameSingular || !record) {
|
const scrollWrapperRef = useContext(ScrollWrapperContext);
|
||||||
|
|
||||||
|
const { ref: cardRef, inView } = useInView({
|
||||||
|
root: scrollWrapperRef.current,
|
||||||
|
rootMargin: '1000px',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!record) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBoardCardWrapper onContextMenu={handleContextMenu}>
|
<StyledBoardCardWrapper onContextMenu={handleContextMenu}>
|
||||||
<StyledBoardCard
|
<StyledBoardCard
|
||||||
|
ref={cardRef}
|
||||||
selected={isCurrentCardSelected}
|
selected={isCurrentCardSelected}
|
||||||
onMouseLeave={onMouseLeaveBoard}
|
onMouseLeave={onMouseLeaveBoard}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -204,7 +218,10 @@ export const RecordBoardCard = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledBoardCardHeader showCompactView={isCompactModeActive}>
|
<StyledBoardCardHeader showCompactView={isCompactModeActive}>
|
||||||
<RecordChip objectNameSingular={objectNameSingular} record={record} />
|
<RecordChip
|
||||||
|
objectNameSingular={objectMetadataItem.nameSingular}
|
||||||
|
record={record}
|
||||||
|
/>
|
||||||
{isCompactModeActive && (
|
{isCompactModeActive && (
|
||||||
<StyledCompactIconContainer className="compact-icon-container">
|
<StyledCompactIconContainer className="compact-icon-container">
|
||||||
<LightIconButton
|
<LightIconButton
|
||||||
@ -226,7 +243,10 @@ export const RecordBoardCard = () => {
|
|||||||
</StyledCheckboxContainer>
|
</StyledCheckboxContainer>
|
||||||
</StyledBoardCardHeader>
|
</StyledBoardCardHeader>
|
||||||
<StyledBoardCardBody>
|
<StyledBoardCardBody>
|
||||||
<AnimatedEaseInOut isOpen={!isCardInCompactMode} initial={false}>
|
<AnimatedEaseInOut
|
||||||
|
isOpen={!isCardInCompactMode || !isCompactModeActive}
|
||||||
|
initial={false}
|
||||||
|
>
|
||||||
{visibleBoardCardFieldDefinitions.map((fieldDefinition) => (
|
{visibleBoardCardFieldDefinitions.map((fieldDefinition) => (
|
||||||
<PreventSelectOnClickContainer
|
<PreventSelectOnClickContainer
|
||||||
key={fieldDefinition.fieldMetadataId}
|
key={fieldDefinition.fieldMetadataId}
|
||||||
@ -249,7 +269,11 @@ export const RecordBoardCard = () => {
|
|||||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordInlineCell />
|
{inView ? (
|
||||||
|
<RecordInlineCell />
|
||||||
|
) : (
|
||||||
|
<StyledRecordInlineCellPlaceholder />
|
||||||
|
)}
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
</PreventSelectOnClickContainer>
|
</PreventSelectOnClickContainer>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -2,14 +2,14 @@ import React, { useContext } from 'react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Draggable, DroppableProvided } from '@hello-pangea/dnd';
|
import { Draggable, DroppableProvided } from '@hello-pangea/dnd';
|
||||||
|
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
import { RecordBoardColumnCardsMemo } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsMemo';
|
import { RecordBoardColumnCardsMemo } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsMemo';
|
||||||
|
import { RecordBoardColumnFetchMoreLoader } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader';
|
||||||
import { RecordBoardColumnNewButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton';
|
import { RecordBoardColumnNewButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton';
|
||||||
|
import { RecordBoardColumnNewOpportunityButton } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton';
|
||||||
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||||
|
|
||||||
const StyledPlaceholder = styled.div`
|
|
||||||
min-height: 1px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledColumnCardsContainer = styled.div`
|
const StyledColumnCardsContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -30,6 +30,7 @@ export const RecordBoardColumnCardsContainer = ({
|
|||||||
droppableProvided,
|
droppableProvided,
|
||||||
}: RecordBoardColumnCardsContainerProps) => {
|
}: RecordBoardColumnCardsContainerProps) => {
|
||||||
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||||
|
const { objectMetadataItem } = useContext(RecordBoardContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledColumnCardsContainer
|
<StyledColumnCardsContainer
|
||||||
@ -38,7 +39,7 @@ export const RecordBoardColumnCardsContainer = ({
|
|||||||
{...droppableProvided?.droppableProps}
|
{...droppableProvided?.droppableProps}
|
||||||
>
|
>
|
||||||
<RecordBoardColumnCardsMemo recordIds={recordIds} />
|
<RecordBoardColumnCardsMemo recordIds={recordIds} />
|
||||||
<StyledPlaceholder>{droppableProvided?.placeholder}</StyledPlaceholder>
|
<RecordBoardColumnFetchMoreLoader />
|
||||||
<Draggable
|
<Draggable
|
||||||
draggableId={`new-${columnDefinition.id}`}
|
draggableId={`new-${columnDefinition.id}`}
|
||||||
index={recordIds.length}
|
index={recordIds.length}
|
||||||
@ -51,7 +52,12 @@ export const RecordBoardColumnCardsContainer = ({
|
|||||||
{...draggableProvided?.draggableProps}
|
{...draggableProvided?.draggableProps}
|
||||||
>
|
>
|
||||||
<StyledNewButtonContainer>
|
<StyledNewButtonContainer>
|
||||||
<RecordBoardColumnNewButton />
|
{objectMetadataItem.nameSingular ===
|
||||||
|
CoreObjectNameSingular.Opportunity ? (
|
||||||
|
<RecordBoardColumnNewOpportunityButton />
|
||||||
|
) : (
|
||||||
|
<RecordBoardColumnNewButton />
|
||||||
|
)}
|
||||||
</StyledNewButtonContainer>
|
</StyledNewButtonContainer>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
import { useInView } from 'react-intersection-observer';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
|
||||||
|
import { grayScale } from '@/ui/theme/constants/colors';
|
||||||
|
|
||||||
|
const StyledText = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: none;
|
||||||
|
color: ${grayScale.gray40};
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
margin-left: ${({ theme }) => theme.spacing(8)};
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RecordBoardColumnFetchMoreLoader = () => {
|
||||||
|
const { getIsFetchingRecordState, getOnFetchMoreVisibilityChangeState } =
|
||||||
|
useRecordBoardStates();
|
||||||
|
const isFetchingRecords = useRecoilValue(getIsFetchingRecordState());
|
||||||
|
|
||||||
|
const onFetchMoreVisibilityChange = useRecoilValue(
|
||||||
|
getOnFetchMoreVisibilityChangeState(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const { ref } = useInView({
|
||||||
|
onChange: onFetchMoreVisibilityChange,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ref}>
|
||||||
|
{isFetchingRecords && <StyledText>Loading more...</StyledText>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
import { useCallback, useContext, useState } from 'react';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
|
||||||
|
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
|
||||||
|
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
|
||||||
|
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
||||||
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
|
import { IconPlus } from '@/ui/display/icon';
|
||||||
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
|
|
||||||
|
const StyledButton = styled.button`
|
||||||
|
align-items: center;
|
||||||
|
align-self: baseline;
|
||||||
|
background-color: ${({ theme }) => theme.background.primary};
|
||||||
|
border: none;
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
padding: ${({ theme }) => theme.spacing(1)};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) => theme.background.tertiary};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RecordBoardColumnNewOpportunityButton = () => {
|
||||||
|
const [isCreatingCard, setIsCreatingCard] = useState(false);
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
const { columnDefinition } = useContext(RecordBoardColumnContext);
|
||||||
|
const { createOneRecord, selectFieldMetadataItem } =
|
||||||
|
useContext(RecordBoardContext);
|
||||||
|
|
||||||
|
const {
|
||||||
|
goBackToPreviousHotkeyScope,
|
||||||
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
|
} = usePreviousHotkeyScope();
|
||||||
|
|
||||||
|
const handleEntitySelect = (company?: EntityForSelect) => {
|
||||||
|
setIsCreatingCard(false);
|
||||||
|
goBackToPreviousHotkeyScope();
|
||||||
|
|
||||||
|
if (!company) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createOneRecord({
|
||||||
|
name: company.name,
|
||||||
|
companyId: company.id,
|
||||||
|
[selectFieldMetadataItem.name]: columnDefinition.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNewClick = useCallback(() => {
|
||||||
|
setIsCreatingCard(true);
|
||||||
|
setHotkeyScopeAndMemorizePreviousScope(
|
||||||
|
RelationPickerHotkeyScope.RelationPicker,
|
||||||
|
);
|
||||||
|
}, [setIsCreatingCard, setHotkeyScopeAndMemorizePreviousScope]);
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
goBackToPreviousHotkeyScope();
|
||||||
|
setIsCreatingCard(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isCreatingCard ? (
|
||||||
|
<SingleEntitySelect
|
||||||
|
disableBackgroundBlur
|
||||||
|
onCancel={handleCancel}
|
||||||
|
onEntitySelected={handleEntitySelect}
|
||||||
|
relationObjectNameSingular={CoreObjectNameSingular.Company}
|
||||||
|
relationPickerScopeId="relation-picker"
|
||||||
|
selectedRelationRecordIds={[]}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<StyledButton onClick={handleNewClick}>
|
||||||
|
<IconPlus size={theme.icon.size.md} />
|
||||||
|
New
|
||||||
|
</StyledButton>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||||
|
|
||||||
|
export const isRecordBoardFetchingRecordsStateScopeMap =
|
||||||
|
createStateScopeMap<boolean>({
|
||||||
|
key: 'isRecordBoardFetchingRecordsStateScopeMap',
|
||||||
|
defaultValue: false,
|
||||||
|
});
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||||
|
|
||||||
|
export const onRecordBoardFetchMoreVisibilityChangeStateScopeMap =
|
||||||
|
createStateScopeMap<(visbility: boolean) => void>({
|
||||||
|
key: 'onRecordBoardFetchMoreVisibilityChangeStateScopeMap',
|
||||||
|
defaultValue: () => {},
|
||||||
|
});
|
||||||
@ -4,6 +4,7 @@ import { FieldInputDraftValue } from '@/object-record/record-field/types/FieldIn
|
|||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { isFieldCurrency } from '@/object-record/record-field/types/guards/isFieldCurrency';
|
import { isFieldCurrency } from '@/object-record/record-field/types/guards/isFieldCurrency';
|
||||||
import { isFieldCurrencyValue } from '@/object-record/record-field/types/guards/isFieldCurrencyValue';
|
import { isFieldCurrencyValue } from '@/object-record/record-field/types/guards/isFieldCurrencyValue';
|
||||||
|
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
|
||||||
import { computeEmptyDraftValue } from '@/object-record/record-field/utils/computeEmptyDraftValue';
|
import { computeEmptyDraftValue } from '@/object-record/record-field/utils/computeEmptyDraftValue';
|
||||||
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
|
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
|
||||||
|
|
||||||
@ -21,18 +22,20 @@ export const computeDraftValueFromFieldValue = <FieldValue>({
|
|||||||
// than the intputDraftValue type as string can be typed anywhere
|
// than the intputDraftValue type as string can be typed anywhere
|
||||||
|
|
||||||
if (isFieldCurrency(fieldDefinition)) {
|
if (isFieldCurrency(fieldDefinition)) {
|
||||||
if (isFieldValueEmpty({ fieldValue, fieldDefinition })) {
|
if (
|
||||||
|
isFieldValueEmpty({ fieldValue, fieldDefinition }) ||
|
||||||
|
!isFieldCurrencyValue(fieldValue)
|
||||||
|
) {
|
||||||
return computeEmptyDraftValue<FieldValue>({ fieldDefinition });
|
return computeEmptyDraftValue<FieldValue>({ fieldDefinition });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFieldCurrencyValue(fieldValue)) {
|
return {
|
||||||
return {
|
amount: fieldValue?.amountMicros ? fieldValue.amountMicros / 1000000 : '',
|
||||||
amount: fieldValue?.amountMicros
|
currenyCode: CurrencyCode.USD,
|
||||||
? fieldValue.amountMicros / 1000000
|
} as unknown as FieldInputDraftValue<FieldValue>;
|
||||||
: '',
|
}
|
||||||
currenyCode: CurrencyCode.USD,
|
if (isFieldRelation(fieldDefinition)) {
|
||||||
} as unknown as FieldInputDraftValue<FieldValue>;
|
return computeEmptyDraftValue<FieldValue>({ fieldDefinition });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fieldValue as FieldInputDraftValue<FieldValue>;
|
return fieldValue as FieldInputDraftValue<FieldValue>;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { isFieldEmail } from '@/object-record/record-field/types/guards/isFieldE
|
|||||||
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
|
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
|
||||||
import { isFieldLink } from '@/object-record/record-field/types/guards/isFieldLink';
|
import { isFieldLink } from '@/object-record/record-field/types/guards/isFieldLink';
|
||||||
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
|
||||||
|
import { isFieldRelationValue } from '@/object-record/record-field/types/guards/isFieldRelationValue';
|
||||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||||
import { isFieldUuid } from '@/object-record/record-field/types/guards/isFieldUuid';
|
import { isFieldUuid } from '@/object-record/record-field/types/guards/isFieldUuid';
|
||||||
|
|
||||||
@ -24,7 +25,8 @@ export const computeEmptyDraftValue = <FieldValue>({
|
|||||||
isFieldText(fieldDefinition) ||
|
isFieldText(fieldDefinition) ||
|
||||||
isFieldDateTime(fieldDefinition) ||
|
isFieldDateTime(fieldDefinition) ||
|
||||||
isFieldNumber(fieldDefinition) ||
|
isFieldNumber(fieldDefinition) ||
|
||||||
isFieldEmail(fieldDefinition)
|
isFieldEmail(fieldDefinition) ||
|
||||||
|
isFieldRelationValue(fieldDefinition)
|
||||||
) {
|
) {
|
||||||
return '' as FieldInputDraftValue<FieldValue>;
|
return '' as FieldInputDraftValue<FieldValue>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
@ -19,7 +19,9 @@ export const RecordIndexBoardContainer = ({
|
|||||||
recordBoardId,
|
recordBoardId,
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}: RecordIndexBoardContainerProps) => {
|
}: RecordIndexBoardContainerProps) => {
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
const { objectMetadataItem } = useObjectMetadataItemOnly({
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
const selectFieldMetadataItem = objectMetadataItem.fields.find(
|
const selectFieldMetadataItem = objectMetadataItem.fields.find(
|
||||||
(field) => field.type === FieldMetadataType.Select,
|
(field) => field.type === FieldMetadataType.Select,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
||||||
import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar';
|
import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar';
|
||||||
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||||
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useRecordBoardSelection';
|
||||||
@ -21,11 +21,35 @@ export const RecordIndexBoardContainerEffect = ({
|
|||||||
recordBoardId,
|
recordBoardId,
|
||||||
viewBarId,
|
viewBarId,
|
||||||
}: RecordIndexBoardContainerEffectProps) => {
|
}: RecordIndexBoardContainerEffectProps) => {
|
||||||
const { objectMetadataItem } = useObjectMetadataItem({
|
const { objectMetadataItem } = useObjectMetadataItemOnly({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
useLoadRecordIndexBoard({ objectNameSingular, recordBoardId, viewBarId });
|
const {
|
||||||
|
setColumns,
|
||||||
|
setObjectSingularName,
|
||||||
|
getSelectedRecordIdsSelector,
|
||||||
|
setFieldDefinitions,
|
||||||
|
getOnFetchMoreVisibilityChangeState,
|
||||||
|
} = useRecordBoard(recordBoardId);
|
||||||
|
|
||||||
|
const { fetchMoreRecords, loading } = useLoadRecordIndexBoard({
|
||||||
|
objectNameSingular,
|
||||||
|
recordBoardId,
|
||||||
|
viewBarId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setOnFetchMoreVisibilityChange = useSetRecoilState(
|
||||||
|
getOnFetchMoreVisibilityChangeState(),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setOnFetchMoreVisibilityChange(() => () => {
|
||||||
|
if (!loading) {
|
||||||
|
fetchMoreRecords?.();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [fetchMoreRecords, loading, setOnFetchMoreVisibilityChange]);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@ -33,12 +57,6 @@ export const RecordIndexBoardContainerEffect = ({
|
|||||||
navigate(`/settings/objects/${objectMetadataItem.namePlural}`);
|
navigate(`/settings/objects/${objectMetadataItem.namePlural}`);
|
||||||
}, [navigate, objectMetadataItem.namePlural]);
|
}, [navigate, objectMetadataItem.namePlural]);
|
||||||
|
|
||||||
const {
|
|
||||||
setColumns,
|
|
||||||
setObjectSingularName,
|
|
||||||
getSelectedRecordIdsSelector,
|
|
||||||
setFieldDefinitions,
|
|
||||||
} = useRecordBoard(recordBoardId);
|
|
||||||
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
|
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -7,13 +7,19 @@ import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/opti
|
|||||||
import { useRecordIndexOptionsForTable } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForTable';
|
import { useRecordIndexOptionsForTable } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForTable';
|
||||||
import { useRecordIndexOptionsImport } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsImport';
|
import { useRecordIndexOptionsImport } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsImport';
|
||||||
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon';
|
import {
|
||||||
|
IconBaselineDensitySmall,
|
||||||
|
IconChevronLeft,
|
||||||
|
IconFileImport,
|
||||||
|
IconTag,
|
||||||
|
} from '@/ui/display/icon';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||||
|
import { MenuItemToggle } from '@/ui/navigation/menu-item/components/MenuItemToggle';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
||||||
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
||||||
@ -86,8 +92,11 @@ export const RecordIndexOptionsDropdownContent = ({
|
|||||||
hiddenBoardFields,
|
hiddenBoardFields,
|
||||||
handleReorderBoardFields,
|
handleReorderBoardFields,
|
||||||
handleBoardFieldVisibilityChange,
|
handleBoardFieldVisibilityChange,
|
||||||
|
isCompactModeActive,
|
||||||
|
setIsCompactModeActive,
|
||||||
} = useRecordIndexOptionsForBoard({
|
} = useRecordIndexOptionsForBoard({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
recordBoardId: recordIndexId,
|
||||||
viewBarId: recordIndexId,
|
viewBarId: recordIndexId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -170,6 +179,20 @@ export const RecordIndexOptionsDropdownContent = ({
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{viewType === ViewType.Kanban && (
|
||||||
|
<>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
<MenuItemToggle
|
||||||
|
LeftIcon={IconBaselineDensitySmall}
|
||||||
|
onToggleChange={setIsCompactModeActive}
|
||||||
|
toggled={isCompactModeActive}
|
||||||
|
text="Compact view"
|
||||||
|
toggleSize="small"
|
||||||
|
/>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,32 +5,48 @@ import { useRecoilState } from 'recoil';
|
|||||||
import { mapBoardFieldDefinitionsToViewFields } from '@/companies/utils/mapBoardFieldDefinitionsToViewFields';
|
import { mapBoardFieldDefinitionsToViewFields } from '@/companies/utils/mapBoardFieldDefinitionsToViewFields';
|
||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
||||||
|
import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
|
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||||
import { useViewFields } from '@/views/hooks/internal/useViewFields';
|
import { useViewFields } from '@/views/hooks/internal/useViewFields';
|
||||||
|
|
||||||
type useRecordIndexOptionsForBoardParams = {
|
type useRecordIndexOptionsForBoardParams = {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
|
recordBoardId: string;
|
||||||
viewBarId: string;
|
viewBarId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useRecordIndexOptionsForBoard = ({
|
export const useRecordIndexOptionsForBoard = ({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
recordBoardId,
|
||||||
viewBarId,
|
viewBarId,
|
||||||
}: useRecordIndexOptionsForBoardParams) => {
|
}: useRecordIndexOptionsForBoardParams) => {
|
||||||
const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] =
|
const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] =
|
||||||
useRecoilState(recordIndexFieldDefinitionsState);
|
useRecoilState(recordIndexFieldDefinitionsState);
|
||||||
|
|
||||||
const { persistViewFields } = useViewFields(viewBarId);
|
const { persistViewFields } = useViewFields(viewBarId);
|
||||||
|
const { getIsCompactModeActiveState } = useRecordBoard(recordBoardId);
|
||||||
|
|
||||||
|
const [isCompactModeActive, setIsCompactModeActive] = useRecoilState(
|
||||||
|
getIsCompactModeActiveState(),
|
||||||
|
);
|
||||||
|
|
||||||
const { objectMetadataItem } = useObjectMetadataItemOnly({
|
const { objectMetadataItem } = useObjectMetadataItemOnly({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { columnDefinitions } =
|
const { columnDefinitions: availableColumnDefinitions } =
|
||||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||||
|
|
||||||
|
// Todo replace this with label identifier logic
|
||||||
|
const columnDefinitions = availableColumnDefinitions
|
||||||
|
.filter(
|
||||||
|
(columnDefinition) => columnDefinition.metadata.fieldName !== 'name',
|
||||||
|
)
|
||||||
|
.filter(filterAvailableTableColumns);
|
||||||
|
|
||||||
const visibleBoardFields = useMemo(
|
const visibleBoardFields = useMemo(
|
||||||
() =>
|
() =>
|
||||||
columnDefinitions.filter((columnDefinition) => {
|
columnDefinitions.filter((columnDefinition) => {
|
||||||
@ -152,5 +168,7 @@ export const useRecordIndexOptionsForBoard = ({
|
|||||||
handleBoardFieldVisibilityChange,
|
handleBoardFieldVisibilityChange,
|
||||||
visibleBoardFields,
|
visibleBoardFields,
|
||||||
hiddenBoardFields,
|
hiddenBoardFields,
|
||||||
|
isCompactModeActive,
|
||||||
|
setIsCompactModeActive,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,8 +5,6 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
||||||
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
||||||
|
|
||||||
import { actionBarOpenState } from '../states/actionBarIsOpenState';
|
|
||||||
|
|
||||||
import { ActionBarItem } from './ActionBarItem';
|
import { ActionBarItem } from './ActionBarItem';
|
||||||
|
|
||||||
const StyledContainerActionBar = styled.div`
|
const StyledContainerActionBar = styled.div`
|
||||||
@ -30,12 +28,11 @@ const StyledContainerActionBar = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ActionBar = () => {
|
export const ActionBar = () => {
|
||||||
const actionBarOpen = useRecoilValue(actionBarOpenState);
|
|
||||||
const contextMenuIsOpen = useRecoilValue(contextMenuIsOpenState);
|
const contextMenuIsOpen = useRecoilValue(contextMenuIsOpenState);
|
||||||
const actionBarEntries = useRecoilValue(actionBarEntriesState);
|
const actionBarEntries = useRecoilValue(actionBarEntriesState);
|
||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
if (!actionBarOpen || contextMenuIsOpen) {
|
if (contextMenuIsOpen) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { useRecoilValue, useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState';
|
|
||||||
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
|
||||||
@ -42,14 +41,12 @@ export const ContextMenu = () => {
|
|||||||
const contextMenuIsOpen = useRecoilValue(contextMenuIsOpenState);
|
const contextMenuIsOpen = useRecoilValue(contextMenuIsOpenState);
|
||||||
const contextMenuEntries = useRecoilValue(contextMenuEntriesState);
|
const contextMenuEntries = useRecoilValue(contextMenuEntriesState);
|
||||||
const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState);
|
const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState);
|
||||||
const setActionBarOpenState = useSetRecoilState(actionBarOpenState);
|
|
||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useListenClickOutside({
|
useListenClickOutside({
|
||||||
refs: [wrapperRef],
|
refs: [wrapperRef],
|
||||||
callback: () => {
|
callback: () => {
|
||||||
setContextMenuOpenState(false);
|
setContextMenuOpenState(false);
|
||||||
setActionBarOpenState(true);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user