@ -1,5 +1,4 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { BoardContext } from '@/companies/states/contexts/BoardContext';
|
||||
import { BoardOptionsDropdown } from '@/ui/layout/board/components/BoardOptionsDropdown';
|
||||
@ -11,7 +10,6 @@ import {
|
||||
import { EntityBoardActionBar } from '@/ui/layout/board/components/EntityBoardActionBar';
|
||||
import { EntityBoardContextMenu } from '@/ui/layout/board/components/EntityBoardContextMenu';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
||||
import { ViewScope } from '@/views/scopes/ViewScope';
|
||||
import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions';
|
||||
|
||||
@ -38,30 +36,12 @@ export const CompanyBoard = ({
|
||||
}: CompanyBoardProps) => {
|
||||
const viewScopeId = 'company-board-view';
|
||||
|
||||
const {
|
||||
currentViewFieldsState,
|
||||
currentViewFiltersState,
|
||||
currentViewSortsState,
|
||||
} = useViewScopedStates({
|
||||
customViewScopeId: viewScopeId,
|
||||
});
|
||||
|
||||
const setCurrentViewFields = useSetRecoilState(currentViewFieldsState);
|
||||
const setCurrentViewFilters = useSetRecoilState(currentViewFiltersState);
|
||||
const setCurrentViewSorts = useSetRecoilState(currentViewSortsState);
|
||||
|
||||
return (
|
||||
<ViewScope
|
||||
viewScopeId={viewScopeId}
|
||||
onViewFieldsChange={(viewFields) => {
|
||||
setCurrentViewFields(viewFields);
|
||||
}}
|
||||
onViewFiltersChange={(viewFilters) => {
|
||||
setCurrentViewFilters(viewFilters);
|
||||
}}
|
||||
onViewSortsChange={(viewSorts) => {
|
||||
setCurrentViewSorts(viewSorts);
|
||||
}}
|
||||
onViewFieldsChange={() => {}}
|
||||
onViewFiltersChange={() => {}}
|
||||
onViewSortsChange={() => {}}
|
||||
>
|
||||
<StyledContainer>
|
||||
<BoardContext.Provider
|
||||
|
||||
@ -127,7 +127,7 @@ const StyledCompactIconContainer = styled.div`
|
||||
export const CompanyBoardCard = () => {
|
||||
const { BoardRecoilScopeContext } = useBoardContext();
|
||||
|
||||
const { currentCardSelected, setCurrentCardSelected } =
|
||||
const { isCurrentCardSelected, setCurrentCardSelected } =
|
||||
useCurrentCardSelected();
|
||||
const boardCardId = useContext(BoardCardIdContext);
|
||||
|
||||
@ -200,9 +200,9 @@ export const CompanyBoardCard = () => {
|
||||
return (
|
||||
<StyledBoardCardWrapper>
|
||||
<StyledBoardCard
|
||||
selected={currentCardSelected}
|
||||
selected={isCurrentCardSelected}
|
||||
onMouseLeave={OnMouseLeaveBoard}
|
||||
onClick={() => setCurrentCardSelected(!currentCardSelected)}
|
||||
onClick={() => setCurrentCardSelected(!isCurrentCardSelected)}
|
||||
>
|
||||
<StyledBoardCardHeader showCompactView={showCompactView}>
|
||||
<CompanyChip
|
||||
@ -225,8 +225,8 @@ export const CompanyBoardCard = () => {
|
||||
)}
|
||||
<StyledCheckboxContainer className="checkbox-container">
|
||||
<Checkbox
|
||||
checked={currentCardSelected}
|
||||
onChange={() => setCurrentCardSelected(!currentCardSelected)}
|
||||
checked={isCurrentCardSelected}
|
||||
onChange={() => setCurrentCardSelected(!isCurrentCardSelected)}
|
||||
variant={CheckboxVariant.Secondary}
|
||||
/>
|
||||
</StyledCheckboxContainer>
|
||||
|
||||
@ -164,21 +164,19 @@ export const HooksCompanyBoardEffect = () => {
|
||||
setViewType?.(ViewType.Kanban);
|
||||
}, [objectMetadataItem, setViewObjectMetadataId, setViewType]);
|
||||
|
||||
const loading = !companies;
|
||||
|
||||
const { setActionBarEntries } = useBoardActionBarEntries();
|
||||
const { setContextMenuEntries } = useBoardContextMenuEntries();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && opportunities && companies) {
|
||||
if (opportunities && companies) {
|
||||
setActionBarEntries();
|
||||
setContextMenuEntries();
|
||||
|
||||
updateCompanyBoard(pipelineSteps, opportunities, companies);
|
||||
setEntityCountInCurrentView(opportunities.length);
|
||||
}
|
||||
}, [
|
||||
companies,
|
||||
loading,
|
||||
opportunities,
|
||||
pipelineSteps,
|
||||
setActionBarEntries,
|
||||
|
||||
@ -105,7 +105,10 @@ export const useUpdateCompanyBoard = () =>
|
||||
position: pipelineStep.position ?? 0,
|
||||
};
|
||||
});
|
||||
if (currentBoardColumns.length === 0) {
|
||||
if (
|
||||
currentBoardColumns.length === 0 &&
|
||||
!isDeeplyEqual(newBoardColumns, currentBoardColumns)
|
||||
) {
|
||||
set(boardColumnsState, newBoardColumns);
|
||||
set(savedBoardColumnsState, newBoardColumns);
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
|
||||
import { useDeleteOneObjectRecord } from '@/object-record/hooks/useDeleteOneObjectRecord';
|
||||
import { currentPipelineState } from '@/pipeline/states/currentPipelineState';
|
||||
import { PipelineStep } from '@/pipeline/types/PipelineStep';
|
||||
import { BoardColumnDefinition } from '@/ui/layout/board/types/BoardColumnDefinition';
|
||||
|
||||
import { currentPipelineState } from '../states/currentPipelineState';
|
||||
|
||||
export const usePipelineSteps = () => {
|
||||
const currentPipeline = useRecoilValue(currentPipelineState);
|
||||
|
||||
const { createOneObject: createOnePipelineStep } =
|
||||
useCreateOneObjectRecord<PipelineStep>({
|
||||
objectNameSingular: 'pipelineStep',
|
||||
@ -20,28 +17,38 @@ export const usePipelineSteps = () => {
|
||||
objectNameSingular: 'pipelineStep',
|
||||
});
|
||||
|
||||
const handlePipelineStepAdd = async (boardColumn: BoardColumnDefinition) => {
|
||||
if (!currentPipeline?.id) return;
|
||||
const handlePipelineStepAdd = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (boardColumn: BoardColumnDefinition) => {
|
||||
const currentPipeline = await snapshot.getPromise(currentPipelineState);
|
||||
if (!currentPipeline?.id) return;
|
||||
|
||||
return createOnePipelineStep?.({
|
||||
variables: {
|
||||
data: {
|
||||
color: boardColumn.colorCode ?? 'gray',
|
||||
id: boardColumn.id,
|
||||
position: boardColumn.position,
|
||||
name: boardColumn.title,
|
||||
pipeline: { connect: { id: currentPipeline.id } },
|
||||
type: 'ongoing',
|
||||
},
|
||||
return createOnePipelineStep?.({
|
||||
variables: {
|
||||
data: {
|
||||
color: boardColumn.colorCode ?? 'gray',
|
||||
id: boardColumn.id,
|
||||
position: boardColumn.position,
|
||||
name: boardColumn.title,
|
||||
pipeline: { connect: { id: currentPipeline.id } },
|
||||
type: 'ongoing',
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
[createOnePipelineStep],
|
||||
);
|
||||
|
||||
const handlePipelineStepDelete = async (boardColumnId: string) => {
|
||||
if (!currentPipeline?.id) return;
|
||||
const handlePipelineStepDelete = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (boardColumnId: string) => {
|
||||
const currentPipeline = await snapshot.getPromise(currentPipelineState);
|
||||
if (!currentPipeline?.id) return;
|
||||
|
||||
return deleteOnePipelineStep?.(boardColumnId);
|
||||
};
|
||||
return deleteOnePipelineStep?.(boardColumnId);
|
||||
},
|
||||
[deleteOnePipelineStep],
|
||||
);
|
||||
|
||||
return { handlePipelineStepAdd, handlePipelineStepDelete };
|
||||
};
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { iconsState } from '@/ui/input/states/iconsState';
|
||||
|
||||
export const useLazyLoadIcons = () => {
|
||||
const [icons, setIcons] = useState<Record<string, IconComponent>>({});
|
||||
const [icons, setIcons] = useRecoilState(iconsState);
|
||||
const [isLoadingIcons, setIsLoadingIcons] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
@ -11,7 +12,7 @@ export const useLazyLoadIcons = () => {
|
||||
setIcons(lazyLoadedIcons);
|
||||
setIsLoadingIcons(false);
|
||||
});
|
||||
}, []);
|
||||
}, [setIcons]);
|
||||
|
||||
return { icons, isLoadingIcons };
|
||||
};
|
||||
|
||||
8
front/src/modules/ui/input/states/iconsState.ts
Normal file
8
front/src/modules/ui/input/states/iconsState.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
|
||||
export const iconsState = atom<Record<string, IconComponent>>({
|
||||
key: 'iconsState',
|
||||
default: {},
|
||||
});
|
||||
@ -1,5 +1,4 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import styled from '@emotion/styled';
|
||||
import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
|
||||
import { useRecoilValue } from 'recoil';
|
||||
@ -9,6 +8,9 @@ import { Opportunity } from '@/pipeline/types/Opportunity';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { StyledBoard } from '@/ui/layout/board/components/StyledBoard';
|
||||
import { BoardColumnContext } from '@/ui/layout/board/contexts/BoardColumnContext';
|
||||
import { useSetCardSelected } from '@/ui/layout/board/hooks/useSetCardSelected';
|
||||
import { useUpdateBoardCardIds } from '@/ui/layout/board/hooks/useUpdateBoardCardIds';
|
||||
import { boardColumnsState } from '@/ui/layout/board/states/boardColumnsState';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useListenClickOutsideByClassName } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
@ -16,10 +18,6 @@ import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { logError } from '~/utils/logError';
|
||||
|
||||
import { useCurrentCardSelected } from '../hooks/useCurrentCardSelected';
|
||||
import { useSetCardSelected } from '../hooks/useSetCardSelected';
|
||||
import { useUpdateBoardCardIds } from '../hooks/useUpdateBoardCardIds';
|
||||
import { boardColumnsState } from '../states/boardColumnsState';
|
||||
import { BoardColumnRecoilScopeContext } from '../states/recoil-scope-contexts/BoardColumnRecoilScopeContext';
|
||||
import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
|
||||
import { BoardOptions } from '../types/BoardOptions';
|
||||
@ -53,16 +51,13 @@ export const EntityBoard = ({
|
||||
onEditColumnTitle,
|
||||
}: EntityBoardProps) => {
|
||||
const boardColumns = useRecoilValue(boardColumnsState);
|
||||
const setCardSelected = useSetCardSelected();
|
||||
|
||||
const { updateOneObject: updateOneOpportunity } =
|
||||
useUpdateOneObjectRecord<Opportunity>({
|
||||
objectNameSingular: 'opportunity',
|
||||
});
|
||||
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const { unselectAllActiveCards } = useCurrentCardSelected();
|
||||
const { unselectAllActiveCards, setCardSelected } = useSetCardSelected();
|
||||
|
||||
const updatePipelineProgressStageInDB = useCallback(
|
||||
async (pipelineProgressId: string, pipelineStepId: string) => {
|
||||
@ -72,19 +67,8 @@ export const EntityBoard = ({
|
||||
pipelineStepId: pipelineStepId,
|
||||
},
|
||||
});
|
||||
|
||||
const cache = apolloClient.cache;
|
||||
cache.modify({
|
||||
id: cache.identify({
|
||||
id: pipelineProgressId,
|
||||
__typename: 'PipelineProgress',
|
||||
}),
|
||||
fields: {
|
||||
pipelineStepId: () => pipelineStepId,
|
||||
},
|
||||
});
|
||||
},
|
||||
[apolloClient.cache, updateOneOpportunity],
|
||||
[updateOneOpportunity],
|
||||
);
|
||||
|
||||
useListenClickOutsideByClassName({
|
||||
@ -135,7 +119,7 @@ export const EntityBoard = ({
|
||||
PageHotkeyScope.OpportunitiesPage,
|
||||
);
|
||||
|
||||
return (boardColumns?.length ?? 0) > 0 ? (
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<StyledBoardHeader />
|
||||
<ScrollWrapper>
|
||||
@ -172,7 +156,5 @@ export const EntityBoard = ({
|
||||
onDragSelectionChange={setCardSelected}
|
||||
/>
|
||||
</StyledWrapper>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { activeCardIdsState } from '@/ui/layout/board/states/activeCardIdsState';
|
||||
import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState';
|
||||
|
||||
import { BoardCardIdContext } from '../contexts/BoardCardIdContext';
|
||||
import { activeCardIdsState } from '../states/activeCardIdsState';
|
||||
import { isCardSelectedFamilyState } from '../states/isCardSelectedFamilyState';
|
||||
|
||||
export const useCurrentCardSelected = () => {
|
||||
const currentCardId = useContext(BoardCardIdContext);
|
||||
|
||||
const isCardSelected = useRecoilValue(
|
||||
const isCurrentCardSelected = useRecoilValue(
|
||||
isCardSelectedFamilyState(currentCardId ?? ''),
|
||||
);
|
||||
|
||||
@ -38,24 +38,8 @@ export const useCurrentCardSelected = () => {
|
||||
[currentCardId, setActiveCardIds],
|
||||
);
|
||||
|
||||
const unselectAllActiveCards = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
() => {
|
||||
const activeCardIds = snapshot.getLoadable(activeCardIdsState).contents;
|
||||
|
||||
activeCardIds.forEach((cardId: string) => {
|
||||
set(isCardSelectedFamilyState(cardId), false);
|
||||
});
|
||||
|
||||
set(activeCardIdsState, []);
|
||||
set(actionBarOpenState, false);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
currentCardSelected: isCardSelected,
|
||||
isCurrentCardSelected,
|
||||
setCurrentCardSelected,
|
||||
unselectAllActiveCards,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState';
|
||||
|
||||
@ -6,15 +6,13 @@ import { activeCardIdsState } from '../states/activeCardIdsState';
|
||||
import { isCardSelectedFamilyState } from '../states/isCardSelectedFamilyState';
|
||||
|
||||
export const useSetCardSelected = () => {
|
||||
const setActionBarOpenState = useSetRecoilState(actionBarOpenState);
|
||||
|
||||
return useRecoilCallback(
|
||||
const setCardSelected = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
(cardId: string, selected: boolean) => {
|
||||
const activeCardIds = snapshot.getLoadable(activeCardIdsState).contents;
|
||||
|
||||
set(isCardSelectedFamilyState(cardId), selected);
|
||||
setActionBarOpenState(selected || activeCardIds.length > 0);
|
||||
set(actionBarOpenState, selected || activeCardIds.length > 0);
|
||||
|
||||
if (selected) {
|
||||
set(activeCardIdsState, [...activeCardIds, cardId]);
|
||||
@ -26,4 +24,24 @@ export const useSetCardSelected = () => {
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const unselectAllActiveCards = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
() => {
|
||||
const activeCardIds = snapshot.getLoadable(activeCardIdsState).contents;
|
||||
|
||||
activeCardIds.forEach((cardId: string) => {
|
||||
set(isCardSelectedFamilyState(cardId), false);
|
||||
});
|
||||
|
||||
set(activeCardIdsState, []);
|
||||
set(actionBarOpenState, false);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
setCardSelected,
|
||||
unselectAllActiveCards,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { CompanyBoard } from '@/companies/board/components/CompanyBoard';
|
||||
import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
|
||||
import { PipelineAddButton } from '@/pipeline/components/PipelineAddButton';
|
||||
import { usePipelineSteps } from '@/pipeline/hooks/usePipelineSteps';
|
||||
@ -14,7 +12,6 @@ import { PageBody } from '@/ui/layout/page/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
||||
import { PageHeader } from '@/ui/layout/page/PageHeader';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { useView } from '@/views/hooks/useView';
|
||||
import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions';
|
||||
|
||||
const StyledBoardContainer = styled.div`
|
||||
@ -46,18 +43,6 @@ export const Opportunities = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const opportunitiesV2MetadataId = useObjectMetadataItem({
|
||||
objectNameSingular: 'opportunity',
|
||||
}).objectMetadataItem?.id;
|
||||
|
||||
const { setViewObjectMetadataId } = useView({
|
||||
viewScopeId: 'company-board-view',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setViewObjectMetadataId?.(opportunitiesV2MetadataId);
|
||||
}, [opportunitiesV2MetadataId, setViewObjectMetadataId]);
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<RecoilScope>
|
||||
|
||||
Reference in New Issue
Block a user