Refactor/scope and context (#1960)
* wip * Test with Dropdown * wip * wip * Finished removing DropdownRecoilScopeContext * Fix from PR
This commit is contained in:
@ -1,8 +1,6 @@
|
|||||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||||
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { PageAddButton } from '@/ui/layout/components/PageAddButton';
|
import { PageAddButton } from '@/ui/layout/components/PageAddButton';
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
import { filtersScopedState } from '@/ui/view-bar/states/filtersScopedState';
|
||||||
import { ActivityType } from '~/generated/graphql';
|
import { ActivityType } from '~/generated/graphql';
|
||||||
@ -26,9 +24,5 @@ export const PageAddTaskButton = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return <PageAddButton onClick={handleClick} />;
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
|
||||||
<PageAddButton onClick={handleClick} />
|
|
||||||
</RecoilScope>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export const PipelineAddButton = () => {
|
|||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
|
||||||
const { closeDropdown, toggleDropdown } = useDropdown({
|
const { closeDropdown, toggleDropdown } = useDropdown({
|
||||||
dropdownId: 'add-pipeline-progress',
|
dropdownScopeId: 'add-pipeline-progress',
|
||||||
});
|
});
|
||||||
|
|
||||||
const createCompanyProgress = useCreateCompanyProgress();
|
const createCompanyProgress = useCreateCompanyProgress();
|
||||||
|
|||||||
@ -3,8 +3,6 @@ import { useSearchParams } from 'react-router-dom';
|
|||||||
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { BoardContext } from '@/companies/states/contexts/BoardContext';
|
import { BoardContext } from '@/companies/states/contexts/BoardContext';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
||||||
@ -19,8 +17,8 @@ import { savedBoardColumnsState } from '../states/savedBoardColumnsState';
|
|||||||
import { canPersistBoardCardFieldsScopedFamilySelector } from '../states/selectors/canPersistBoardCardFieldsScopedFamilySelector';
|
import { canPersistBoardCardFieldsScopedFamilySelector } from '../states/selectors/canPersistBoardCardFieldsScopedFamilySelector';
|
||||||
import { canPersistBoardColumnsSelector } from '../states/selectors/canPersistBoardColumnsSelector';
|
import { canPersistBoardColumnsSelector } from '../states/selectors/canPersistBoardColumnsSelector';
|
||||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||||
import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
|
||||||
import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
|
import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
|
||||||
|
import { BoardScopeIds } from '../types/enums/BoardScopeIds';
|
||||||
|
|
||||||
import { BoardOptionsDropdown } from './BoardOptionsDropdown';
|
import { BoardOptionsDropdown } from './BoardOptionsDropdown';
|
||||||
|
|
||||||
@ -101,27 +99,25 @@ export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
|
|||||||
const canPersistView = canPersistBoardCardFields || canPersistBoardColumns;
|
const canPersistView = canPersistBoardCardFields || canPersistBoardColumns;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<ViewBarContext.Provider
|
||||||
<ViewBarContext.Provider
|
value={{
|
||||||
value={{
|
...viewBarContextProps,
|
||||||
...viewBarContextProps,
|
canPersistViewFields: canPersistView,
|
||||||
canPersistViewFields: canPersistView,
|
onCurrentViewSubmit: handleCurrentViewSubmit,
|
||||||
onCurrentViewSubmit: handleCurrentViewSubmit,
|
onViewBarReset: handleViewBarReset,
|
||||||
onViewBarReset: handleViewBarReset,
|
onViewSelect: handleViewSelect,
|
||||||
onViewSelect: handleViewSelect,
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<ViewBar
|
||||||
<ViewBar
|
className={className}
|
||||||
className={className}
|
optionsDropdownButton={
|
||||||
optionsDropdownButton={
|
<BoardOptionsDropdown
|
||||||
<BoardOptionsDropdown
|
customHotkeyScope={{ scope: BoardOptionsHotkeyScope.Dropdown }}
|
||||||
customHotkeyScope={{ scope: BoardOptionsHotkeyScope.Dropdown }}
|
onStageAdd={onStageAdd}
|
||||||
onStageAdd={onStageAdd}
|
/>
|
||||||
/>
|
}
|
||||||
}
|
optionsDropdownScopeId={BoardScopeIds.OptionsDropdown}
|
||||||
optionsDropdownKey={BoardOptionsDropdownKey}
|
/>
|
||||||
/>
|
</ViewBarContext.Provider>
|
||||||
</ViewBarContext.Provider>
|
|
||||||
</RecoilScope>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { useResetRecoilState } from 'recoil';
|
|||||||
import { ViewBarDropdownButton } from '@/ui/view-bar/components/ViewBarDropdownButton';
|
import { ViewBarDropdownButton } from '@/ui/view-bar/components/ViewBarDropdownButton';
|
||||||
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
||||||
|
|
||||||
import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
import { BoardScopeIds } from '../types/enums/BoardScopeIds';
|
||||||
|
|
||||||
import { BoardOptionsDropdownButton } from './BoardOptionsDropdownButton';
|
import { BoardOptionsDropdownButton } from './BoardOptionsDropdownButton';
|
||||||
import {
|
import {
|
||||||
@ -32,7 +32,7 @@ export const BoardOptionsDropdown = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={customHotkeyScope}
|
dropdownHotkeyScope={customHotkeyScope}
|
||||||
dropdownId={BoardOptionsDropdownKey}
|
dropdownId={BoardScopeIds.OptionsDropdown}
|
||||||
onClickOutside={resetViewEditMode}
|
onClickOutside={resetViewEditMode}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
||||||
|
|
||||||
import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
import { BoardScopeIds } from '../types/enums/BoardScopeIds';
|
||||||
|
|
||||||
export const BoardOptionsDropdownButton = () => {
|
export const BoardOptionsDropdownButton = () => {
|
||||||
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
||||||
dropdownId: BoardOptionsDropdownKey,
|
dropdownScopeId: BoardScopeIds.OptionsDropdown,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
|
|||||||
@ -43,7 +43,6 @@ import { savedBoardCardFieldsFamilyState } from '../states/savedBoardCardFieldsF
|
|||||||
import { hiddenBoardCardFieldsScopedSelector } from '../states/selectors/hiddenBoardCardFieldsScopedSelector';
|
import { hiddenBoardCardFieldsScopedSelector } from '../states/selectors/hiddenBoardCardFieldsScopedSelector';
|
||||||
import { visibleBoardCardFieldsScopedSelector } from '../states/selectors/visibleBoardCardFieldsScopedSelector';
|
import { visibleBoardCardFieldsScopedSelector } from '../states/selectors/visibleBoardCardFieldsScopedSelector';
|
||||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||||
import { BoardOptionsDropdownKey } from '../types/BoardOptionsDropdownKey';
|
|
||||||
|
|
||||||
export type BoardOptionsDropdownContentProps = {
|
export type BoardOptionsDropdownContentProps = {
|
||||||
customHotkeyScope: HotkeyScope;
|
customHotkeyScope: HotkeyScope;
|
||||||
@ -144,9 +143,7 @@ export const BoardOptionsDropdownContent = ({
|
|||||||
|
|
||||||
const { handleFieldVisibilityChange } = useBoardCardFields();
|
const { handleFieldVisibilityChange } = useBoardCardFields();
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown({
|
const { closeDropdown } = useDropdown();
|
||||||
dropdownId: BoardOptionsDropdownKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
Key.Escape,
|
Key.Escape,
|
||||||
|
|||||||
@ -3,8 +3,6 @@ import { userEvent, within } from '@storybook/testing-library';
|
|||||||
|
|
||||||
import { BoardContext } from '@/companies/states/contexts/BoardContext';
|
import { BoardContext } from '@/companies/states/contexts/BoardContext';
|
||||||
import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
|
import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
||||||
@ -26,9 +24,7 @@ const meta: Meta<typeof BoardOptionsDropdown> = {
|
|||||||
ViewBarRecoilScopeContext: parameters.customRecoilScopeContext,
|
ViewBarRecoilScopeContext: parameters.customRecoilScopeContext,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<Story />
|
||||||
<Story />
|
|
||||||
</RecoilScope>
|
|
||||||
</ViewBarContext.Provider>
|
</ViewBarContext.Provider>
|
||||||
</BoardContext.Provider>
|
</BoardContext.Provider>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export const BoardOptionsDropdownKey = 'board-options';
|
|
||||||
3
front/src/modules/ui/board/types/enums/BoardScopeIds.ts
Normal file
3
front/src/modules/ui/board/types/enums/BoardScopeIds.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export enum BoardScopeIds {
|
||||||
|
OptionsDropdown = 'board-options',
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
||||||
|
import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope';
|
||||||
import { FieldMetadata } from '@/ui/field/types/FieldMetadata';
|
import { FieldMetadata } from '@/ui/field/types/FieldMetadata';
|
||||||
|
|
||||||
import { ColumnDefinition } from '../types/ColumnDefinition';
|
import { ColumnDefinition } from '../types/ColumnDefinition';
|
||||||
@ -20,19 +21,20 @@ export const ColumnHeadWithDropdown = ({
|
|||||||
primaryColumnKey,
|
primaryColumnKey,
|
||||||
}: ColumnHeadWithDropdownProps) => {
|
}: ColumnHeadWithDropdownProps) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownScope dropdownScopeId={column.key + '-header'}>
|
||||||
clickableComponent={<ColumnHead column={column} />}
|
<DropdownMenu
|
||||||
dropdownId={column.key + '-header'}
|
clickableComponent={<ColumnHead column={column} />}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DataTableColumnDropdownMenu
|
<DataTableColumnDropdownMenu
|
||||||
column={column}
|
column={column}
|
||||||
isFirstColumn={isFirstColumn}
|
isFirstColumn={isFirstColumn}
|
||||||
isLastColumn={isLastColumn}
|
isLastColumn={isLastColumn}
|
||||||
primaryColumnKey={primaryColumnKey}
|
primaryColumnKey={primaryColumnKey}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: column.key + '-header' }}
|
dropdownHotkeyScope={{ scope: column.key + '-header' }}
|
||||||
dropdownOffset={{ x: 0, y: -8 }}
|
dropdownOffset={{ x: 0, y: -8 }}
|
||||||
/>
|
/>
|
||||||
|
</DropdownScope>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export const DataTableColumnDropdownMenu = ({
|
|||||||
useTableColumns();
|
useTableColumns();
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown({
|
const { closeDropdown } = useDropdown({
|
||||||
dropdownId: ColumnHeadDropdownId,
|
dropdownScopeId: ColumnHeadDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleColumnMoveLeft = () => {
|
const handleColumnMoveLeft = () => {
|
||||||
|
|||||||
@ -3,10 +3,8 @@ import styled from '@emotion/styled';
|
|||||||
import { useRecoilCallback, useRecoilState } from 'recoil';
|
import { useRecoilCallback, useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { IconButton } from '@/ui/button/components/IconButton';
|
import { IconButton } from '@/ui/button/components/IconButton';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { IconPlus } from '@/ui/icon';
|
import { IconPlus } from '@/ui/icon';
|
||||||
import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer';
|
import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer';
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
|
|
||||||
import { useTableColumns } from '../hooks/useTableColumns';
|
import { useTableColumns } from '../hooks/useTableColumns';
|
||||||
@ -177,36 +175,33 @@ export const DataTableHeader = () => {
|
|||||||
>
|
>
|
||||||
<SelectAllCheckbox />
|
<SelectAllCheckbox />
|
||||||
</th>
|
</th>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
{visibleTableColumns.map((column, index) => (
|
||||||
{visibleTableColumns.map((column, index) => (
|
<StyledColumnHeaderCell
|
||||||
<StyledColumnHeaderCell
|
key={column.key}
|
||||||
key={column.key}
|
isResizing={resizedFieldKey === column.key}
|
||||||
isResizing={resizedFieldKey === column.key}
|
columnWidth={Math.max(
|
||||||
columnWidth={Math.max(
|
tableColumnsByKey[column.key].size +
|
||||||
tableColumnsByKey[column.key].size +
|
(resizedFieldKey === column.key ? resizeFieldOffset : 0),
|
||||||
(resizedFieldKey === column.key ? resizeFieldOffset : 0),
|
COLUMN_MIN_WIDTH,
|
||||||
COLUMN_MIN_WIDTH,
|
)}
|
||||||
)}
|
>
|
||||||
>
|
<StyledColumnHeadContainer>
|
||||||
<StyledColumnHeadContainer>
|
<ColumnHeadWithDropdown
|
||||||
<ColumnHeadWithDropdown
|
column={column}
|
||||||
column={column}
|
isFirstColumn={index === 1}
|
||||||
isFirstColumn={index === 1}
|
isLastColumn={index === visibleTableColumns.length - 1}
|
||||||
isLastColumn={index === visibleTableColumns.length - 1}
|
primaryColumnKey={primaryColumn.key}
|
||||||
primaryColumnKey={primaryColumn.key}
|
|
||||||
/>
|
|
||||||
</StyledColumnHeadContainer>
|
|
||||||
|
|
||||||
<StyledResizeHandler
|
|
||||||
className="cursor-col-resize"
|
|
||||||
role="separator"
|
|
||||||
onPointerDown={() => {
|
|
||||||
setResizedFieldKey(column.key);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</StyledColumnHeaderCell>
|
</StyledColumnHeadContainer>
|
||||||
))}
|
<StyledResizeHandler
|
||||||
</RecoilScope>
|
className="cursor-col-resize"
|
||||||
|
role="separator"
|
||||||
|
onPointerDown={() => {
|
||||||
|
setResizedFieldKey(column.key);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</StyledColumnHeaderCell>
|
||||||
|
))}
|
||||||
|
|
||||||
<th>
|
<th>
|
||||||
{hiddenTableColumns.length > 0 && (
|
{hiddenTableColumns.length > 0 && (
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
|||||||
|
|
||||||
export const TableOptionsDropdownButton = () => {
|
export const TableOptionsDropdownButton = () => {
|
||||||
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
||||||
dropdownId: TableOptionsDropdownId,
|
dropdownScopeId: TableOptionsDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import { currentViewScopedSelector } from '@/ui/view-bar/states/selectors/curren
|
|||||||
import { viewsByIdScopedSelector } from '@/ui/view-bar/states/selectors/viewsByIdScopedSelector';
|
import { viewsByIdScopedSelector } from '@/ui/view-bar/states/selectors/viewsByIdScopedSelector';
|
||||||
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
import { viewEditModeState } from '@/ui/view-bar/states/viewEditModeState';
|
||||||
|
|
||||||
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
|
|
||||||
import { useTableColumns } from '../../hooks/useTableColumns';
|
import { useTableColumns } from '../../hooks/useTableColumns';
|
||||||
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
|
import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
|
||||||
@ -37,9 +36,7 @@ export const TableOptionsDropdownContent = () => {
|
|||||||
const scopeId = useRecoilScopeId(TableRecoilScopeContext);
|
const scopeId = useRecoilScopeId(TableRecoilScopeContext);
|
||||||
|
|
||||||
const { onImport } = useContext(ViewBarContext);
|
const { onImport } = useContext(ViewBarContext);
|
||||||
const { closeDropdown } = useDropdown({
|
const { closeDropdown } = useDropdown();
|
||||||
dropdownId: TableOptionsDropdownId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { userEvent, within } from '@storybook/testing-library';
|
import { userEvent, within } from '@storybook/testing-library';
|
||||||
|
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||||
import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
@ -20,9 +19,7 @@ const meta: Meta<typeof TableOptionsDropdown> = {
|
|||||||
ViewBarRecoilScopeContext: TableRecoilScopeContext,
|
ViewBarRecoilScopeContext: TableRecoilScopeContext,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<Story />
|
||||||
<Story />
|
|
||||||
</RecoilScope>
|
|
||||||
</ViewBarContext.Provider>
|
</ViewBarContext.Provider>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import { useContext } from 'react';
|
|||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
||||||
import { ViewBar } from '@/ui/view-bar/components/ViewBar';
|
import { ViewBar } from '@/ui/view-bar/components/ViewBar';
|
||||||
import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
import { ViewBarContext } from '@/ui/view-bar/contexts/ViewBarContext';
|
||||||
@ -34,23 +32,21 @@ export const TableHeader = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<ViewBarContext.Provider
|
||||||
<ViewBarContext.Provider
|
value={{
|
||||||
value={{
|
...viewBarContextProps,
|
||||||
...viewBarContextProps,
|
onCurrentViewSubmit,
|
||||||
onCurrentViewSubmit,
|
onViewSelect: handleViewSelect,
|
||||||
onViewSelect: handleViewSelect,
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<ViewBar
|
||||||
<ViewBar
|
optionsDropdownButton={
|
||||||
optionsDropdownButton={
|
<TableOptionsDropdown
|
||||||
<TableOptionsDropdown
|
customHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
||||||
customHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
/>
|
||||||
/>
|
}
|
||||||
}
|
optionsDropdownScopeId={TableOptionsDropdownId}
|
||||||
optionsDropdownKey={TableOptionsDropdownId}
|
/>
|
||||||
/>
|
</ViewBarContext.Provider>
|
||||||
</ViewBarContext.Provider>
|
|
||||||
</RecoilScope>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,6 @@ import { DropdownToggleEffect } from './DropdownToggleEffect';
|
|||||||
type DropdownMenuProps = {
|
type DropdownMenuProps = {
|
||||||
clickableComponent?: JSX.Element | JSX.Element[];
|
clickableComponent?: JSX.Element | JSX.Element[];
|
||||||
dropdownComponents: JSX.Element | JSX.Element[];
|
dropdownComponents: JSX.Element | JSX.Element[];
|
||||||
dropdownId: string;
|
|
||||||
hotkey?: {
|
hotkey?: {
|
||||||
key: Keys;
|
key: Keys;
|
||||||
scope: string;
|
scope: string;
|
||||||
@ -32,7 +31,6 @@ type DropdownMenuProps = {
|
|||||||
export const DropdownMenu = ({
|
export const DropdownMenu = ({
|
||||||
clickableComponent,
|
clickableComponent,
|
||||||
dropdownComponents,
|
dropdownComponents,
|
||||||
dropdownId,
|
|
||||||
hotkey,
|
hotkey,
|
||||||
dropdownHotkeyScope,
|
dropdownHotkeyScope,
|
||||||
dropdownPlacement = 'bottom-end',
|
dropdownPlacement = 'bottom-end',
|
||||||
@ -43,9 +41,7 @@ export const DropdownMenu = ({
|
|||||||
}: DropdownMenuProps) => {
|
}: DropdownMenuProps) => {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { isDropdownOpen, toggleDropdown, closeDropdown } = useDropdown({
|
const { isDropdownOpen, toggleDropdown, closeDropdown } = useDropdown();
|
||||||
dropdownId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { refs, floatingStyles } = useFloating({
|
const { refs, floatingStyles } = useFloating({
|
||||||
placement: dropdownPlacement,
|
placement: dropdownPlacement,
|
||||||
@ -71,8 +67,7 @@ export const DropdownMenu = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
useInternalHotkeyScopeManagement({
|
useInternalHotkeyScopeManagement({
|
||||||
dropdownId,
|
dropdownHotkeyScopeFromParent: dropdownHotkeyScope,
|
||||||
dropdownHotkeyScope,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
@ -83,6 +78,7 @@ export const DropdownMenu = ({
|
|||||||
dropdownHotkeyScope.scope,
|
dropdownHotkeyScope.scope,
|
||||||
[closeDropdown],
|
[closeDropdown],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef}>
|
<div ref={containerRef}>
|
||||||
{clickableComponent && (
|
{clickableComponent && (
|
||||||
@ -101,11 +97,7 @@ export const DropdownMenu = ({
|
|||||||
{dropdownComponents}
|
{dropdownComponents}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<DropdownToggleEffect
|
<DropdownToggleEffect onDropdownClose={onClose} onDropdownOpen={onOpen} />
|
||||||
dropdownId={dropdownId}
|
|
||||||
onDropdownClose={onClose}
|
|
||||||
onDropdownOpen={onOpen}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,15 +3,13 @@ import { useEffect } from 'react';
|
|||||||
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
||||||
|
|
||||||
export const DropdownToggleEffect = ({
|
export const DropdownToggleEffect = ({
|
||||||
dropdownId,
|
|
||||||
onDropdownClose,
|
onDropdownClose,
|
||||||
onDropdownOpen,
|
onDropdownOpen,
|
||||||
}: {
|
}: {
|
||||||
dropdownId: string;
|
|
||||||
onDropdownClose?: () => void;
|
onDropdownClose?: () => void;
|
||||||
onDropdownOpen?: () => void;
|
onDropdownOpen?: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { isDropdownOpen } = useDropdown({ dropdownId });
|
const { isDropdownOpen } = useDropdown();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDropdownOpen) {
|
if (isDropdownOpen) {
|
||||||
|
|||||||
@ -1,47 +1,52 @@
|
|||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState';
|
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||||
|
|
||||||
import { dropdownButtonHotkeyScopeScopedFamilyState } from '../states/dropdownButtonHotkeyScopeScopedFamilyState';
|
import { DropdownScopeInternalContext } from '../scopes/scope-internal-context/DropdownScopeInternalContext';
|
||||||
import { isDropdownButtonOpenScopedFamilyState } from '../states/isDropdownButtonOpenScopedFamilyState';
|
|
||||||
import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
|
|
||||||
export const useDropdown = ({ dropdownId }: { dropdownId: string }) => {
|
import { useDropdownStates } from './useDropdownStates';
|
||||||
|
|
||||||
|
type UseDropdownProps = {
|
||||||
|
dropdownScopeId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDropdown = (props?: UseDropdownProps) => {
|
||||||
const {
|
const {
|
||||||
setHotkeyScopeAndMemorizePreviousScope,
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
goBackToPreviousHotkeyScope,
|
goBackToPreviousHotkeyScope,
|
||||||
} = usePreviousHotkeyScope();
|
} = usePreviousHotkeyScope();
|
||||||
|
|
||||||
const [isDropdownButtonOpen, setIsDropdownButtonOpen] =
|
const scopeId = useAvailableScopeIdOrThrow(
|
||||||
useRecoilScopedFamilyState(
|
DropdownScopeInternalContext,
|
||||||
isDropdownButtonOpenScopedFamilyState,
|
props?.dropdownScopeId,
|
||||||
dropdownId,
|
|
||||||
DropdownRecoilScopeContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [dropdownButtonHotkeyScope] = useRecoilScopedFamilyState(
|
|
||||||
dropdownButtonHotkeyScopeScopedFamilyState,
|
|
||||||
dropdownId,
|
|
||||||
DropdownRecoilScopeContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
dropdownHotkeyScope,
|
||||||
|
setDropdownHotkeyScope,
|
||||||
|
isDropdownOpen,
|
||||||
|
setIsDropdownOpen,
|
||||||
|
} = useDropdownStates({
|
||||||
|
scopeId,
|
||||||
|
});
|
||||||
|
|
||||||
const closeDropdownButton = () => {
|
const closeDropdownButton = () => {
|
||||||
goBackToPreviousHotkeyScope();
|
goBackToPreviousHotkeyScope();
|
||||||
setIsDropdownButtonOpen(false);
|
setIsDropdownOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDropdownButton = () => {
|
const openDropdownButton = () => {
|
||||||
setIsDropdownButtonOpen(true);
|
setIsDropdownOpen(true);
|
||||||
|
|
||||||
if (dropdownButtonHotkeyScope) {
|
if (dropdownHotkeyScope) {
|
||||||
setHotkeyScopeAndMemorizePreviousScope(
|
setHotkeyScopeAndMemorizePreviousScope(
|
||||||
dropdownButtonHotkeyScope.scope,
|
dropdownHotkeyScope.scope,
|
||||||
dropdownButtonHotkeyScope.customScopes,
|
dropdownHotkeyScope.customScopes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleDropdownButton = () => {
|
const toggleDropdownButton = () => {
|
||||||
if (isDropdownButtonOpen) {
|
if (isDropdownOpen) {
|
||||||
closeDropdownButton();
|
closeDropdownButton();
|
||||||
} else {
|
} else {
|
||||||
openDropdownButton();
|
openDropdownButton();
|
||||||
@ -49,9 +54,12 @@ export const useDropdown = ({ dropdownId }: { dropdownId: string }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isDropdownOpen: isDropdownButtonOpen,
|
isDropdownOpen: isDropdownOpen,
|
||||||
closeDropdown: closeDropdownButton,
|
closeDropdown: closeDropdownButton,
|
||||||
toggleDropdown: toggleDropdownButton,
|
toggleDropdown: toggleDropdownButton,
|
||||||
openDropdown: openDropdownButton,
|
openDropdown: openDropdownButton,
|
||||||
|
scopeId,
|
||||||
|
dropdownHotkeyScope,
|
||||||
|
setDropdownHotkeyScope,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
23
front/src/modules/ui/dropdown/hooks/useDropdownStates.ts
Normal file
23
front/src/modules/ui/dropdown/hooks/useDropdownStates.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
|
||||||
|
|
||||||
|
import { dropdownHotkeyScopeScopedState } from '../states/dropdownHotkeyScopeScopedState';
|
||||||
|
import { isDropdownOpenScopedState } from '../states/isDropdownOpenScopedState';
|
||||||
|
|
||||||
|
export const useDropdownStates = ({ scopeId }: { scopeId: string }) => {
|
||||||
|
const [isDropdownOpen, setIsDropdownOpen] = useRecoilScopedStateV2(
|
||||||
|
isDropdownOpenScopedState,
|
||||||
|
scopeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [dropdownHotkeyScope, setDropdownHotkeyScope] = useRecoilScopedStateV2(
|
||||||
|
dropdownHotkeyScopeScopedState,
|
||||||
|
scopeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isDropdownOpen,
|
||||||
|
setIsDropdownOpen,
|
||||||
|
dropdownHotkeyScope,
|
||||||
|
setDropdownHotkeyScope,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,33 +1,24 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState';
|
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
import { dropdownButtonHotkeyScopeScopedFamilyState } from '../states/dropdownButtonHotkeyScopeScopedFamilyState';
|
import { useDropdown } from './useDropdown';
|
||||||
import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
|
|
||||||
export const useInternalHotkeyScopeManagement = ({
|
export const useInternalHotkeyScopeManagement = ({
|
||||||
dropdownId,
|
dropdownHotkeyScopeFromParent,
|
||||||
dropdownHotkeyScope,
|
|
||||||
}: {
|
}: {
|
||||||
dropdownId: string;
|
dropdownHotkeyScopeFromParent?: HotkeyScope;
|
||||||
dropdownHotkeyScope?: HotkeyScope;
|
|
||||||
}) => {
|
}) => {
|
||||||
const [dropdownButtonHotkeyScope, setDropdownButtonHotkeyScope] =
|
const { dropdownHotkeyScope, setDropdownHotkeyScope } = useDropdown();
|
||||||
useRecoilScopedFamilyState(
|
|
||||||
dropdownButtonHotkeyScopeScopedFamilyState,
|
|
||||||
dropdownId,
|
|
||||||
DropdownRecoilScopeContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isDeeplyEqual(dropdownButtonHotkeyScope, dropdownHotkeyScope)) {
|
if (!isDeeplyEqual(dropdownHotkeyScopeFromParent, dropdownHotkeyScope)) {
|
||||||
setDropdownButtonHotkeyScope(dropdownHotkeyScope);
|
setDropdownHotkeyScope(dropdownHotkeyScopeFromParent);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
dropdownHotkeyScope,
|
dropdownHotkeyScope,
|
||||||
dropdownButtonHotkeyScope,
|
dropdownHotkeyScopeFromParent,
|
||||||
setDropdownButtonHotkeyScope,
|
setDropdownHotkeyScope,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
19
front/src/modules/ui/dropdown/scopes/DropdownScope.tsx
Normal file
19
front/src/modules/ui/dropdown/scopes/DropdownScope.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { DropdownScopeInternalContext } from './scope-internal-context/DropdownScopeInternalContext';
|
||||||
|
|
||||||
|
type DropdownScopeProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
dropdownScopeId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DropdownScope = ({
|
||||||
|
children,
|
||||||
|
dropdownScopeId,
|
||||||
|
}: DropdownScopeProps) => {
|
||||||
|
return (
|
||||||
|
<DropdownScopeInternalContext.Provider value={{ scopeId: dropdownScopeId }}>
|
||||||
|
{children}
|
||||||
|
</DropdownScopeInternalContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey';
|
||||||
|
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
|
||||||
|
|
||||||
|
type DropdownScopeInternalContextProps = ScopedStateKey & {
|
||||||
|
test?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DropdownScopeInternalContext =
|
||||||
|
createScopeInternalContext<DropdownScopeInternalContextProps>();
|
||||||
@ -1,11 +0,0 @@
|
|||||||
import { atomFamily } from 'recoil';
|
|
||||||
|
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
|
||||||
|
|
||||||
export const dropdownButtonHotkeyScopeScopedFamilyState = atomFamily<
|
|
||||||
HotkeyScope | null | undefined,
|
|
||||||
string
|
|
||||||
>({
|
|
||||||
key: 'dropdownButtonHotkeyScopeScopedFamilyState',
|
|
||||||
default: null,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||||
|
|
||||||
|
export const dropdownHotkeyScopeScopedState = createScopedState<
|
||||||
|
HotkeyScope | null | undefined
|
||||||
|
>({
|
||||||
|
key: 'dropdownHotkeyScopeScopedState',
|
||||||
|
defaultValue: null,
|
||||||
|
});
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import { atomFamily } from 'recoil';
|
|
||||||
|
|
||||||
export const isDropdownButtonOpenScopedFamilyState = atomFamily<
|
|
||||||
boolean,
|
|
||||||
string
|
|
||||||
>({
|
|
||||||
key: 'isDropdownButtonOpenScopedState',
|
|
||||||
default: false,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||||
|
|
||||||
|
export const isDropdownOpenScopedState = createScopedState<boolean>({
|
||||||
|
key: 'isDropdownOpenScopedState',
|
||||||
|
defaultValue: false,
|
||||||
|
});
|
||||||
@ -1,3 +0,0 @@
|
|||||||
import { createContext } from 'react';
|
|
||||||
|
|
||||||
export const DropdownRecoilScopeContext = createContext<string | null>(null);
|
|
||||||
@ -8,6 +8,7 @@ import { CountryCallingCode } from 'libphonenumber-js';
|
|||||||
|
|
||||||
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
||||||
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/dropdown/hooks/useDropdown';
|
||||||
|
import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope';
|
||||||
import { IconChevronDown } from '@/ui/icon';
|
import { IconChevronDown } from '@/ui/icon';
|
||||||
|
|
||||||
import { IconWorld } from '../constants/icons';
|
import { IconWorld } from '../constants/icons';
|
||||||
@ -77,7 +78,7 @@ export const CountryPickerDropdownButton = ({
|
|||||||
const [selectedCountry, setSelectedCountry] = useState<Country>();
|
const [selectedCountry, setSelectedCountry] = useState<Country>();
|
||||||
|
|
||||||
const { isDropdownOpen, closeDropdown } = useDropdown({
|
const { isDropdownOpen, closeDropdown } = useDropdown({
|
||||||
dropdownId: 'country-picker',
|
dropdownScopeId: 'country-picker',
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleChange = (countryCode: string) => {
|
const handleChange = (countryCode: string) => {
|
||||||
@ -122,25 +123,26 @@ export const CountryPickerDropdownButton = ({
|
|||||||
}, [countries, value]);
|
}, [countries, value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownScope dropdownScopeId="country-picker">
|
||||||
dropdownId="country-picker"
|
<DropdownMenu
|
||||||
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
|
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
|
||||||
clickableComponent={
|
clickableComponent={
|
||||||
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
|
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
|
||||||
<StyledIconContainer>
|
<StyledIconContainer>
|
||||||
{selectedCountry ? <selectedCountry.Flag /> : <IconWorld />}
|
{selectedCountry ? <selectedCountry.Flag /> : <IconWorld />}
|
||||||
<IconChevronDown size={theme.icon.size.sm} />
|
<IconChevronDown size={theme.icon.size.sm} />
|
||||||
</StyledIconContainer>
|
</StyledIconContainer>
|
||||||
</StyledDropdownButtonContainer>
|
</StyledDropdownButtonContainer>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<CountryPickerDropdownSelect
|
<CountryPickerDropdownSelect
|
||||||
countries={countries}
|
countries={countries}
|
||||||
selectedCountry={selectedCountry}
|
selectedCountry={selectedCountry}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownOffset={{ x: -60, y: -34 }}
|
dropdownOffset={{ x: -60, y: -34 }}
|
||||||
/>
|
/>
|
||||||
|
</DropdownScope>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,9 +2,6 @@ import { useEffect, useRef, useState } from 'react';
|
|||||||
import ReactPhoneNumberInput from 'react-phone-number-input';
|
import ReactPhoneNumberInput from 'react-phone-number-input';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
|
||||||
|
|
||||||
import { useRegisterInputEvents } from '../hooks/useRegisterInputEvents';
|
import { useRegisterInputEvents } from '../hooks/useRegisterInputEvents';
|
||||||
|
|
||||||
import { CountryPickerDropdownButton } from './CountryPickerDropdownButton';
|
import { CountryPickerDropdownButton } from './CountryPickerDropdownButton';
|
||||||
@ -86,17 +83,15 @@ export const PhoneInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer ref={wrapperRef}>
|
<StyledContainer ref={wrapperRef}>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<StyledCustomPhoneInput
|
||||||
<StyledCustomPhoneInput
|
autoFocus={autoFocus}
|
||||||
autoFocus={autoFocus}
|
placeholder="Phone number"
|
||||||
placeholder="Phone number"
|
value={value}
|
||||||
value={value}
|
onChange={setInternalValue}
|
||||||
onChange={setInternalValue}
|
international={true}
|
||||||
international={true}
|
withCountryCallingCode={true}
|
||||||
withCountryCallingCode={true}
|
countrySelectComponent={CountryPickerDropdownButton}
|
||||||
countrySelectComponent={CountryPickerDropdownButton}
|
/>
|
||||||
/>
|
|
||||||
</RecoilScope>
|
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export const ShowPageAddButton = ({
|
|||||||
entity: ActivityTargetableEntity;
|
entity: ActivityTargetableEntity;
|
||||||
}) => {
|
}) => {
|
||||||
const { closeDropdown, toggleDropdown } = useDropdown({
|
const { closeDropdown, toggleDropdown } = useDropdown({
|
||||||
dropdownId: 'add-show-page',
|
dropdownScopeId: 'add-show-page',
|
||||||
});
|
});
|
||||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,10 @@ import { RecoilScopeContext as RecoilScopeContextType } from '@/types/RecoilScop
|
|||||||
|
|
||||||
import { RecoilScopeContext } from '../states/RecoilScopeContext';
|
import { RecoilScopeContext } from '../states/RecoilScopeContext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @deprecated Use a custom scope context instead, see example with DropdownScope
|
||||||
|
*/
|
||||||
export const RecoilScope = ({
|
export const RecoilScope = ({
|
||||||
children,
|
children,
|
||||||
scopeId,
|
scopeId,
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import { Context, useContext } from 'react';
|
import { Context, useContext } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use a custom scope instead and desctructure the scope id from the scope context
|
||||||
|
* Get the scope context with useScopeInternalContext
|
||||||
|
*/
|
||||||
export const useContextScopeId = (SpecificContext: Context<string | null>) => {
|
export const useContextScopeId = (SpecificContext: Context<string | null>) => {
|
||||||
const recoilScopeId = useContext(SpecificContext);
|
const recoilScopeId = useContext(SpecificContext);
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import { useContext } from 'react';
|
|||||||
|
|
||||||
import { RecoilScopeContext } from '@/types/RecoilScopeContext';
|
import { RecoilScopeContext } from '@/types/RecoilScopeContext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use a custom scope instead and desctructure the scope id from the scope context
|
||||||
|
*/
|
||||||
export const useRecoilScopeId = (RecoilScopeContext: RecoilScopeContext) => {
|
export const useRecoilScopeId = (RecoilScopeContext: RecoilScopeContext) => {
|
||||||
const recoilScopeId = useContext(RecoilScopeContext);
|
const recoilScopeId = useContext(RecoilScopeContext);
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,21 @@
|
|||||||
import { Context, useContext } from 'react';
|
import { RecoilState, SerializableParam, useRecoilState } from 'recoil';
|
||||||
import { RecoilState, useRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { RecoilScopeContext } from '../states/RecoilScopeContext';
|
import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey';
|
||||||
|
|
||||||
export const useRecoilScopedFamilyState = <StateType>(
|
export const useRecoilScopedFamilyState = <
|
||||||
recoilState: (familyUniqueId: string) => RecoilState<StateType>,
|
StateType,
|
||||||
uniqueIdInRecoilScope: string,
|
FamilyKey extends SerializableParam,
|
||||||
CustomRecoilScopeContext?: Context<string | null>,
|
>(
|
||||||
|
recoilState: (
|
||||||
|
scopedFamilyKey: ScopedFamilyStateKey<FamilyKey>,
|
||||||
|
) => RecoilState<StateType>,
|
||||||
|
scopeId: string,
|
||||||
|
familyKey: FamilyKey,
|
||||||
) => {
|
) => {
|
||||||
const recoilScopeId = useContext(
|
return useRecoilState<StateType>(
|
||||||
CustomRecoilScopeContext ?? RecoilScopeContext,
|
recoilState({
|
||||||
|
scopeId,
|
||||||
|
familyKey,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!recoilScopeId)
|
|
||||||
throw new Error(
|
|
||||||
`Using a scoped atom without a RecoilScope : ${
|
|
||||||
recoilState('').key
|
|
||||||
}, verify that you are using a RecoilScope with a specific context if you intended to do so.`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const familyUniqueId = recoilScopeId + uniqueIdInRecoilScope;
|
|
||||||
|
|
||||||
return useRecoilState<StateType>(recoilState(familyUniqueId));
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { RecoilState, useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
|
||||||
|
|
||||||
|
export const useRecoilScopedStateV2 = <StateType>(
|
||||||
|
recoilState: (scopedKey: ScopedStateKey) => RecoilState<StateType>,
|
||||||
|
scopeId: string,
|
||||||
|
) => {
|
||||||
|
return useRecoilState<StateType>(
|
||||||
|
recoilState({
|
||||||
|
scopeId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -3,6 +3,9 @@ import { RecoilState, RecoilValueReadOnly, useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { RecoilScopeContext } from '../states/RecoilScopeContext';
|
import { RecoilScopeContext } from '../states/RecoilScopeContext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use useRecoilScopedStateV2 instead
|
||||||
|
*/
|
||||||
export const useRecoilScopedValue = <T>(
|
export const useRecoilScopedValue = <T>(
|
||||||
recoilState: (param: string) => RecoilState<T> | RecoilValueReadOnly<T>,
|
recoilState: (param: string) => RecoilState<T> | RecoilValueReadOnly<T>,
|
||||||
CustomRecoilScopeContext?: Context<string | null>,
|
CustomRecoilScopeContext?: Context<string | null>,
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { RecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
|
||||||
|
|
||||||
|
export const useRecoilScopedValueV2 = <StateType>(
|
||||||
|
recoilState: (scopedKey: ScopedStateKey) => RecoilState<StateType>,
|
||||||
|
scopeId: string,
|
||||||
|
) => {
|
||||||
|
return useRecoilValue<StateType>(
|
||||||
|
recoilState({
|
||||||
|
scopeId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import { ScopeInternalContext } from '../types/ScopeInternalContext';
|
||||||
|
|
||||||
|
import { useScopeInternalContext } from './useScopeInternalContext';
|
||||||
|
|
||||||
|
export const useAvailableScopeIdOrThrow = <T extends { scopeId: string }>(
|
||||||
|
Context: ScopeInternalContext<T>,
|
||||||
|
scopeIdFromProps?: string,
|
||||||
|
): string => {
|
||||||
|
const scopeInternalContext = useScopeInternalContext(Context);
|
||||||
|
|
||||||
|
const scopeIdFromContext = scopeInternalContext?.scopeId;
|
||||||
|
|
||||||
|
if (scopeIdFromProps) {
|
||||||
|
return scopeIdFromProps;
|
||||||
|
} else if (scopeIdFromContext) {
|
||||||
|
return scopeIdFromContext;
|
||||||
|
} else {
|
||||||
|
throw new Error('Scope id is not provided and cannot be found in context.');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
import { ScopeInternalContext } from '../types/ScopeInternalContext';
|
||||||
|
|
||||||
|
export const useScopeInternalContext = <T extends { scopeId: string }>(
|
||||||
|
Context: ScopeInternalContext<T>,
|
||||||
|
) => {
|
||||||
|
const context = useContext(Context);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
import { ScopeInternalContext } from '../types/ScopeInternalContext';
|
||||||
|
|
||||||
|
export const useScopeInternalContextOrThrow = <T extends { scopeId: string }>(
|
||||||
|
Context: ScopeInternalContext<T>,
|
||||||
|
) => {
|
||||||
|
const context = useContext(Context);
|
||||||
|
|
||||||
|
if (!isDefined(context)) {
|
||||||
|
throw new Error(
|
||||||
|
`Using a scope context without a ScopeInternalContext.Provider wrapper for context : ${Context.displayName}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
import { Context } from 'react';
|
||||||
|
|
||||||
|
export type ScopeInternalContext<T extends { scopeId: string }> =
|
||||||
|
Context<T | null>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { SerializableParam } from 'recoil';
|
||||||
|
|
||||||
|
export type ScopedFamilyStateKey<FamilyKey extends SerializableParam> = {
|
||||||
|
scopeId: string;
|
||||||
|
familyKey: FamilyKey;
|
||||||
|
};
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
export type ScopedStateKey = {
|
||||||
|
scopeId: string;
|
||||||
|
};
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { Context, createContext } from 'react';
|
||||||
|
|
||||||
|
import { ScopedStateKey } from '../types/ScopedStateKey';
|
||||||
|
|
||||||
|
type ScopeInternalContext<T extends ScopedStateKey> = Context<T | null>;
|
||||||
|
|
||||||
|
export const createScopeInternalContext = <T extends ScopedStateKey>(
|
||||||
|
initialValue?: T,
|
||||||
|
) => {
|
||||||
|
return createContext<T | null>(
|
||||||
|
initialValue ?? null,
|
||||||
|
) as ScopeInternalContext<T>;
|
||||||
|
};
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import { atomFamily, SerializableParam } from 'recoil';
|
||||||
|
|
||||||
|
import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey';
|
||||||
|
|
||||||
|
export const createScopedFamilyState = <
|
||||||
|
ValueType,
|
||||||
|
FamilyKey extends SerializableParam,
|
||||||
|
>({
|
||||||
|
key,
|
||||||
|
defaultValue,
|
||||||
|
}: {
|
||||||
|
key: string;
|
||||||
|
defaultValue: ValueType;
|
||||||
|
}) => {
|
||||||
|
return atomFamily<ValueType, ScopedFamilyStateKey<FamilyKey>>({
|
||||||
|
key,
|
||||||
|
default: defaultValue,
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
|
export const createScopedState = <ValueType>({
|
||||||
|
key,
|
||||||
|
defaultValue,
|
||||||
|
}: {
|
||||||
|
key: string;
|
||||||
|
defaultValue: ValueType;
|
||||||
|
}) => {
|
||||||
|
return atomFamily<ValueType, { scopeId: string }>({
|
||||||
|
key,
|
||||||
|
default: defaultValue,
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -6,7 +6,7 @@ import { FilterDropdownId } from '../constants/FilterDropdownId';
|
|||||||
|
|
||||||
export const AddFilterFromDropdownButton = () => {
|
export const AddFilterFromDropdownButton = () => {
|
||||||
const { toggleDropdown } = useDropdown({
|
const { toggleDropdown } = useDropdown({
|
||||||
dropdownId: FilterDropdownId,
|
dropdownScopeId: FilterDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export const MultipleFiltersButton = () => {
|
|||||||
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
||||||
|
|
||||||
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
const { isDropdownOpen, toggleDropdown } = useDropdown({
|
||||||
dropdownId: FilterDropdownId,
|
dropdownScopeId: FilterDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
|
const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
|
||||||
|
|||||||
@ -1,22 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
|
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
||||||
import { DropdownMenuContainer } from '@/ui/dropdown/components/DropdownMenuContainer';
|
import { DropdownMenuContainer } from '@/ui/dropdown/components/DropdownMenuContainer';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
import { StyledHeaderDropdownButton } from '@/ui/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { IconChevronDown } from '@/ui/icon';
|
import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { IconChevronDown } from '@/ui/icon/index';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { filterDefinitionUsedInDropdownScopedState } from '@/ui/view-bar/states/filterDefinitionUsedInDropdownScopedState';
|
import { filterDefinitionUsedInDropdownScopedState } from '@/ui/view-bar/states/filterDefinitionUsedInDropdownScopedState';
|
||||||
import { filterDropdownSearchInputScopedState } from '@/ui/view-bar/states/filterDropdownSearchInputScopedState';
|
|
||||||
import { selectedOperandInDropdownScopedState } from '@/ui/view-bar/states/selectedOperandInDropdownScopedState';
|
import { selectedOperandInDropdownScopedState } from '@/ui/view-bar/states/selectedOperandInDropdownScopedState';
|
||||||
|
|
||||||
import { StyledHeaderDropdownButton } from '../../dropdown/components/StyledHeaderDropdownButton';
|
|
||||||
import { useViewBarContext } from '../hooks/useViewBarContext';
|
import { useViewBarContext } from '../hooks/useViewBarContext';
|
||||||
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
|
||||||
import { filtersScopedState } from '../states/filtersScopedState';
|
import { filtersScopedState } from '../states/filtersScopedState';
|
||||||
import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState';
|
|
||||||
import { FilterOperand } from '../types/FilterOperand';
|
import { FilterOperand } from '../types/FilterOperand';
|
||||||
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
|
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
|
||||||
|
|
||||||
@ -24,19 +21,11 @@ import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInp
|
|||||||
import { FilterDropdownEntitySelect } from './FilterDropdownEntitySelect';
|
import { FilterDropdownEntitySelect } from './FilterDropdownEntitySelect';
|
||||||
import { GenericEntityFilterChip } from './GenericEntityFilterChip';
|
import { GenericEntityFilterChip } from './GenericEntityFilterChip';
|
||||||
|
|
||||||
const StyledDropdownButtonContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
position: relative;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const SingleEntityFilterDropdownButton = ({
|
export const SingleEntityFilterDropdownButton = ({
|
||||||
hotkeyScope,
|
hotkeyScope,
|
||||||
}: {
|
}: {
|
||||||
hotkeyScope: HotkeyScope;
|
hotkeyScope: HotkeyScope;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
const { ViewBarRecoilScopeContext } = useViewBarContext();
|
||||||
|
|
||||||
const [availableFilters] = useRecoilScopedState(
|
const [availableFilters] = useRecoilScopedState(
|
||||||
@ -45,12 +34,6 @@ export const SingleEntityFilterDropdownButton = ({
|
|||||||
);
|
);
|
||||||
const availableFilter = availableFilters[0];
|
const availableFilter = availableFilters[0];
|
||||||
|
|
||||||
const [isFilterDropdownUnfolded, setIsFilterDropdownUnfolded] =
|
|
||||||
useRecoilScopedState(
|
|
||||||
isFilterDropdownUnfoldedScopedState,
|
|
||||||
DropdownRecoilScopeContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [filters] = useRecoilScopedState(
|
const [filters] = useRecoilScopedState(
|
||||||
filtersScopedState,
|
filtersScopedState,
|
||||||
ViewBarRecoilScopeContext,
|
ViewBarRecoilScopeContext,
|
||||||
@ -61,11 +44,6 @@ export const SingleEntityFilterDropdownButton = ({
|
|||||||
ViewBarRecoilScopeContext,
|
ViewBarRecoilScopeContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [, setFilterDropdownSearchInput] = useRecoilScopedState(
|
|
||||||
filterDropdownSearchInputScopedState,
|
|
||||||
ViewBarRecoilScopeContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setSelectedOperandInDropdown] = useRecoilScopedState(
|
const [, setSelectedOperandInDropdown] = useRecoilScopedState(
|
||||||
selectedOperandInDropdownScopedState,
|
selectedOperandInDropdownScopedState,
|
||||||
ViewBarRecoilScopeContext,
|
ViewBarRecoilScopeContext,
|
||||||
@ -81,45 +59,37 @@ export const SingleEntityFilterDropdownButton = ({
|
|||||||
setSelectedOperandInDropdown,
|
setSelectedOperandInDropdown,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const theme = useTheme();
|
||||||
|
|
||||||
const handleIsUnfoldedChange = (newIsUnfolded: boolean) => {
|
|
||||||
if (newIsUnfolded) {
|
|
||||||
setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes);
|
|
||||||
setIsFilterDropdownUnfolded(true);
|
|
||||||
} else {
|
|
||||||
setHotkeyScope(hotkeyScope.scope, hotkeyScope.customScopes);
|
|
||||||
setIsFilterDropdownUnfolded(false);
|
|
||||||
setFilterDropdownSearchInput('');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDropdownButtonContainer data-select-disable>
|
<DropdownScope dropdownScopeId="single-entity-filter-dropdown">
|
||||||
<StyledHeaderDropdownButton
|
<DropdownMenu
|
||||||
isUnfolded={isFilterDropdownUnfolded}
|
dropdownHotkeyScope={hotkeyScope}
|
||||||
onClick={() => handleIsUnfoldedChange(!isFilterDropdownUnfolded)}
|
dropdownOffset={{ x: 0, y: -28 }}
|
||||||
>
|
clickableComponent={
|
||||||
{filters[0] ? (
|
<StyledHeaderDropdownButton>
|
||||||
<GenericEntityFilterChip
|
{filters[0] ? (
|
||||||
filter={filters[0]}
|
<GenericEntityFilterChip
|
||||||
Icon={
|
filter={filters[0]}
|
||||||
filters[0].operand === FilterOperand.IsNotNull
|
Icon={
|
||||||
? availableFilter.SelectAllIcon
|
filters[0].operand === FilterOperand.IsNotNull
|
||||||
: undefined
|
? availableFilter.SelectAllIcon
|
||||||
}
|
: undefined
|
||||||
/>
|
}
|
||||||
) : (
|
/>
|
||||||
'Filter'
|
) : (
|
||||||
)}
|
'Filter'
|
||||||
<IconChevronDown size={theme.icon.size.md} />
|
)}
|
||||||
</StyledHeaderDropdownButton>
|
<IconChevronDown size={theme.icon.size.md} />
|
||||||
{isFilterDropdownUnfolded && (
|
</StyledHeaderDropdownButton>
|
||||||
<DropdownMenuContainer onClose={() => handleIsUnfoldedChange(false)}>
|
}
|
||||||
<FilterDropdownEntitySearchInput />
|
dropdownComponents={
|
||||||
<FilterDropdownEntitySelect />
|
<DropdownMenuContainer>
|
||||||
</DropdownMenuContainer>
|
<FilterDropdownEntitySearchInput />
|
||||||
)}
|
<FilterDropdownEntitySelect />
|
||||||
</StyledDropdownButtonContainer>
|
</DropdownMenuContainer>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</DropdownScope>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export const SortDropdownButton = ({
|
|||||||
const isSortSelected = sorts.length > 0;
|
const isSortSelected = sorts.length > 0;
|
||||||
|
|
||||||
const { toggleDropdown } = useDropdown({
|
const { toggleDropdown } = useDropdown({
|
||||||
dropdownId: SortDropdownId,
|
dropdownScopeId: SortDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleButtonClick = () => {
|
const handleButtonClick = () => {
|
||||||
|
|||||||
@ -15,16 +15,16 @@ import { ViewsDropdownButton } from './ViewsDropdownButton';
|
|||||||
export type ViewBarProps = {
|
export type ViewBarProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
optionsDropdownButton: ReactNode;
|
optionsDropdownButton: ReactNode;
|
||||||
optionsDropdownKey: string;
|
optionsDropdownScopeId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewBar = ({
|
export const ViewBar = ({
|
||||||
className,
|
className,
|
||||||
optionsDropdownButton,
|
optionsDropdownButton,
|
||||||
optionsDropdownKey,
|
optionsDropdownScopeId,
|
||||||
}: ViewBarProps) => {
|
}: ViewBarProps) => {
|
||||||
const { openDropdown: openOptionsDropdownButton } = useDropdown({
|
const { openDropdown: openOptionsDropdownButton } = useDropdown({
|
||||||
dropdownId: optionsDropdownKey,
|
dropdownScopeId: optionsDropdownScopeId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Keys } from 'react-hotkeys-hook';
|
|||||||
import { Placement } from '@floating-ui/react';
|
import { Placement } from '@floating-ui/react';
|
||||||
|
|
||||||
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
||||||
|
import { DropdownScope } from '@/ui/dropdown/scopes/DropdownScope';
|
||||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||||
|
|
||||||
type ViewBarDropdownButtonProps = {
|
type ViewBarDropdownButtonProps = {
|
||||||
@ -31,17 +32,18 @@ export const ViewBarDropdownButton = ({
|
|||||||
onOpen,
|
onOpen,
|
||||||
}: ViewBarDropdownButtonProps) => {
|
}: ViewBarDropdownButtonProps) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownScope dropdownScopeId={dropdownId}>
|
||||||
clickableComponent={buttonComponent}
|
<DropdownMenu
|
||||||
dropdownComponents={dropdownComponents}
|
clickableComponent={buttonComponent}
|
||||||
dropdownId={dropdownId}
|
dropdownComponents={dropdownComponents}
|
||||||
hotkey={hotkey}
|
hotkey={hotkey}
|
||||||
dropdownHotkeyScope={dropdownHotkeyScope}
|
dropdownHotkeyScope={dropdownHotkeyScope}
|
||||||
dropdownOffset={{ x: 0, y: 8 }}
|
dropdownOffset={{ x: 0, y: 8 }}
|
||||||
dropdownPlacement={dropdownPlacement}
|
dropdownPlacement={dropdownPlacement}
|
||||||
onClickOutside={onClickOutside}
|
onClickOutside={onClickOutside}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onOpen={onOpen}
|
onOpen={onOpen}
|
||||||
/>
|
/>
|
||||||
|
</DropdownScope>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -105,7 +105,7 @@ export const ViewsDropdownButton = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { isDropdownOpen, closeDropdown } = useDropdown({
|
const { isDropdownOpen, closeDropdown } = useDropdown({
|
||||||
dropdownId: ViewsDropdownId,
|
dropdownScopeId: ViewsDropdownId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const setViewEditMode = useSetRecoilState(viewEditModeState);
|
const setViewEditMode = useSetRecoilState(viewEditModeState);
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import { DataTableContextMenu } from '@/ui/data-table/context-menu/components/Da
|
|||||||
import { useUpsertDataTableItem } from '@/ui/data-table/hooks/useUpsertDataTableItem';
|
import { useUpsertDataTableItem } from '@/ui/data-table/hooks/useUpsertDataTableItem';
|
||||||
import { useUpsertTableRowId } from '@/ui/data-table/hooks/useUpsertTableRowId';
|
import { useUpsertTableRowId } from '@/ui/data-table/hooks/useUpsertTableRowId';
|
||||||
import { TableRecoilScopeContext } from '@/ui/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '@/ui/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { IconBuildingSkyscraper } from '@/ui/icon';
|
import { IconBuildingSkyscraper } from '@/ui/icon';
|
||||||
import { PageAddButton } from '@/ui/layout/components/PageAddButton';
|
import { PageAddButton } from '@/ui/layout/components/PageAddButton';
|
||||||
import { PageBody } from '@/ui/layout/components/PageBody';
|
import { PageBody } from '@/ui/layout/components/PageBody';
|
||||||
@ -58,10 +57,8 @@ export const Companies = () => {
|
|||||||
<SpreadsheetImportProvider>
|
<SpreadsheetImportProvider>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<PageHeader title="Companies" Icon={IconBuildingSkyscraper}>
|
<PageHeader title="Companies" Icon={IconBuildingSkyscraper}>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
||||||
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
<PageAddButton onClick={handleAddButtonClick} />
|
||||||
<PageAddButton onClick={handleAddButtonClick} />
|
|
||||||
</RecoilScope>
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<RecoilScope
|
<RecoilScope
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import { CompanyTeam } from '@/companies/components/CompanyTeam';
|
|||||||
import { useCompanyQuery } from '@/companies/hooks/useCompanyQuery';
|
import { useCompanyQuery } from '@/companies/hooks/useCompanyQuery';
|
||||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { FieldContext } from '@/ui/field/contexts/FieldContext';
|
import { FieldContext } from '@/ui/field/contexts/FieldContext';
|
||||||
import { IconBuildingSkyscraper } from '@/ui/icon';
|
import { IconBuildingSkyscraper } from '@/ui/icon';
|
||||||
import { InlineCell } from '@/ui/inline-cell/components/InlineCell';
|
import { InlineCell } from '@/ui/inline-cell/components/InlineCell';
|
||||||
@ -62,19 +61,17 @@ export const CompanyShow = () => {
|
|||||||
hasBackButton
|
hasBackButton
|
||||||
Icon={IconBuildingSkyscraper}
|
Icon={IconBuildingSkyscraper}
|
||||||
>
|
>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<PageFavoriteButton
|
||||||
<PageFavoriteButton
|
isFavorite={isFavorite}
|
||||||
isFavorite={isFavorite}
|
onClick={handleFavoriteButtonClick}
|
||||||
onClick={handleFavoriteButtonClick}
|
/>
|
||||||
/>
|
<ShowPageAddButton
|
||||||
<ShowPageAddButton
|
key="add"
|
||||||
key="add"
|
entity={{
|
||||||
entity={{
|
id: company.id,
|
||||||
id: company.id,
|
type: ActivityTargetableEntityType.Company,
|
||||||
type: ActivityTargetableEntityType.Company,
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</RecoilScope>
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope-
|
|||||||
import { PipelineAddButton } from '@/pipeline/components/PipelineAddButton';
|
import { PipelineAddButton } from '@/pipeline/components/PipelineAddButton';
|
||||||
import { usePipelineStages } from '@/pipeline/hooks/usePipelineStages';
|
import { usePipelineStages } from '@/pipeline/hooks/usePipelineStages';
|
||||||
import { BoardOptionsContext } from '@/ui/board/contexts/BoardOptionsContext';
|
import { BoardOptionsContext } from '@/ui/board/contexts/BoardOptionsContext';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { IconTargetArrow } from '@/ui/icon';
|
import { IconTargetArrow } from '@/ui/icon';
|
||||||
import { PageBody } from '@/ui/layout/components/PageBody';
|
import { PageBody } from '@/ui/layout/components/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/components/PageContainer';
|
import { PageContainer } from '@/ui/layout/components/PageContainer';
|
||||||
@ -44,9 +43,7 @@ export const Opportunities = () => {
|
|||||||
<PageContainer>
|
<PageContainer>
|
||||||
<RecoilScope>
|
<RecoilScope>
|
||||||
<PageHeader title="Opportunities" Icon={IconTargetArrow}>
|
<PageHeader title="Opportunities" Icon={IconTargetArrow}>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<PipelineAddButton />
|
||||||
<PipelineAddButton />
|
|
||||||
</RecoilScope>
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<BoardOptionsContext.Provider value={opportunitiesBoardOptions}>
|
<BoardOptionsContext.Provider value={opportunitiesBoardOptions}>
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import { DataTableContextMenu } from '@/ui/data-table/context-menu/components/Da
|
|||||||
import { useUpsertDataTableItem } from '@/ui/data-table/hooks/useUpsertDataTableItem';
|
import { useUpsertDataTableItem } from '@/ui/data-table/hooks/useUpsertDataTableItem';
|
||||||
import { useUpsertTableRowId } from '@/ui/data-table/hooks/useUpsertTableRowId';
|
import { useUpsertTableRowId } from '@/ui/data-table/hooks/useUpsertTableRowId';
|
||||||
import { TableRecoilScopeContext } from '@/ui/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '@/ui/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { IconUser } from '@/ui/icon';
|
import { IconUser } from '@/ui/icon';
|
||||||
import { PageAddButton } from '@/ui/layout/components/PageAddButton';
|
import { PageAddButton } from '@/ui/layout/components/PageAddButton';
|
||||||
import { PageBody } from '@/ui/layout/components/PageBody';
|
import { PageBody } from '@/ui/layout/components/PageBody';
|
||||||
@ -54,10 +53,8 @@ export const People = () => {
|
|||||||
<SpreadsheetImportProvider>
|
<SpreadsheetImportProvider>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<PageHeader title="People" Icon={IconUser}>
|
<PageHeader title="People" Icon={IconUser}>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
||||||
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
<PageAddButton onClick={handleAddButtonClick} />
|
||||||
<PageAddButton onClick={handleAddButtonClick} />
|
|
||||||
</RecoilScope>
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<RecoilScope
|
<RecoilScope
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { useFavorites } from '@/favorites/hooks/useFavorites';
|
|||||||
import { GET_PERSON } from '@/people/graphql/queries/getPerson';
|
import { GET_PERSON } from '@/people/graphql/queries/getPerson';
|
||||||
import { usePersonQuery } from '@/people/hooks/usePersonQuery';
|
import { usePersonQuery } from '@/people/hooks/usePersonQuery';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { FieldContext } from '@/ui/field/contexts/FieldContext';
|
import { FieldContext } from '@/ui/field/contexts/FieldContext';
|
||||||
import { IconUser } from '@/ui/icon';
|
import { IconUser } from '@/ui/icon';
|
||||||
import { InlineCell } from '@/ui/inline-cell/components/InlineCell';
|
import { InlineCell } from '@/ui/inline-cell/components/InlineCell';
|
||||||
@ -77,27 +76,25 @@ export const PersonShow = () => {
|
|||||||
<PageContainer>
|
<PageContainer>
|
||||||
<PageTitle title={person.displayName || 'No Name'} />
|
<PageTitle title={person.displayName || 'No Name'} />
|
||||||
<PageHeader title={person.firstName ?? ''} Icon={IconUser} hasBackButton>
|
<PageHeader title={person.firstName ?? ''} Icon={IconUser} hasBackButton>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<PageFavoriteButton
|
||||||
<PageFavoriteButton
|
isFavorite={isFavorite}
|
||||||
isFavorite={isFavorite}
|
onClick={handleFavoriteButtonClick}
|
||||||
onClick={handleFavoriteButtonClick}
|
/>
|
||||||
/>
|
<ShowPageAddButton
|
||||||
<ShowPageAddButton
|
key="add"
|
||||||
key="add"
|
entity={{
|
||||||
entity={{
|
id: person.id,
|
||||||
id: person.id,
|
type: ActivityTargetableEntityType.Person,
|
||||||
type: ActivityTargetableEntityType.Person,
|
relatedEntities: person.company?.id
|
||||||
relatedEntities: person.company?.id
|
? [
|
||||||
? [
|
{
|
||||||
{
|
id: person.company?.id,
|
||||||
id: person.company?.id,
|
type: ActivityTargetableEntityType.Company,
|
||||||
type: ActivityTargetableEntityType.Company,
|
},
|
||||||
},
|
]
|
||||||
]
|
: undefined,
|
||||||
: undefined,
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</RecoilScope>
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import styled from '@emotion/styled';
|
|||||||
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
||||||
import { PageAddTaskButton } from '@/activities/tasks/components/PageAddTaskButton';
|
import { PageAddTaskButton } from '@/activities/tasks/components/PageAddTaskButton';
|
||||||
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
||||||
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
|
||||||
import { IconArchive, IconCheck, IconCheckbox } from '@/ui/icon/index';
|
import { IconArchive, IconCheck, IconCheckbox } from '@/ui/icon/index';
|
||||||
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
import { PageBody } from '@/ui/layout/components/PageBody';
|
import { PageBody } from '@/ui/layout/components/PageBody';
|
||||||
@ -48,43 +47,41 @@ export const Tasks = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<RecoilScope CustomRecoilScopeContext={DropdownRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={TasksRecoilScopeContext}>
|
||||||
<RecoilScope CustomRecoilScopeContext={TasksRecoilScopeContext}>
|
<TasksEffect />
|
||||||
<TasksEffect />
|
<PageHeader title="Tasks" Icon={IconCheckbox}>
|
||||||
<PageHeader title="Tasks" Icon={IconCheckbox}>
|
<PageAddTaskButton />
|
||||||
<PageAddTaskButton />
|
</PageHeader>
|
||||||
</PageHeader>
|
<PageBody>
|
||||||
<PageBody>
|
{/* TODO: we should refactor filters as a standalone module ? */}
|
||||||
{/* TODO: we should refactor filters as a standalone module ? */}
|
<ViewBarContext.Provider
|
||||||
<ViewBarContext.Provider
|
value={{
|
||||||
value={{
|
ViewBarRecoilScopeContext: TasksRecoilScopeContext,
|
||||||
ViewBarRecoilScopeContext: TasksRecoilScopeContext,
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<StyledTasksContainer>
|
||||||
<StyledTasksContainer>
|
<TopBar
|
||||||
<TopBar
|
leftComponent={
|
||||||
leftComponent={
|
<StyledTabListContainer>
|
||||||
<StyledTabListContainer>
|
<TabList
|
||||||
<TabList
|
context={TasksRecoilScopeContext}
|
||||||
context={TasksRecoilScopeContext}
|
tabs={TASK_TABS}
|
||||||
tabs={TASK_TABS}
|
|
||||||
/>
|
|
||||||
</StyledTabListContainer>
|
|
||||||
}
|
|
||||||
rightComponent={
|
|
||||||
<FilterDropdownButton
|
|
||||||
key="tasks-filter-dropdown-button"
|
|
||||||
hotkeyScope={{
|
|
||||||
scope: RelationPickerHotkeyScope.RelationPicker,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
}
|
</StyledTabListContainer>
|
||||||
/>
|
}
|
||||||
<TaskGroups />
|
rightComponent={
|
||||||
</StyledTasksContainer>
|
<FilterDropdownButton
|
||||||
</ViewBarContext.Provider>
|
key="tasks-filter-dropdown-button"
|
||||||
</PageBody>
|
hotkeyScope={{
|
||||||
</RecoilScope>
|
scope: RelationPickerHotkeyScope.RelationPicker,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<TaskGroups />
|
||||||
|
</StyledTasksContainer>
|
||||||
|
</ViewBarContext.Provider>
|
||||||
|
</PageBody>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
3
front/src/types/ScopeContextProps.ts
Normal file
3
front/src/types/ScopeContextProps.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type ScopeContextProps<T = unknown> = {
|
||||||
|
scopeId: string;
|
||||||
|
} & T;
|
||||||
Reference in New Issue
Block a user