Added all the initial selection logic (#14789)

Added initial implementation of calendar card selection logic 

---

Video -> 
[Screencast from 2025-09-30
19-50-56.webm](https://github.com/user-attachments/assets/757e5dbe-9936-4633-9178-d42a20401b82)

---
@Weiko

---------

Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
This commit is contained in:
Saurav Jain
2025-09-30 22:18:49 +05:30
committed by GitHub
parent f33396e425
commit 8b2e43c448
8 changed files with 152 additions and 3 deletions
@@ -5,6 +5,15 @@ import { RecordCalendarMonth } from '@/object-record/record-calendar/month/compo
import { RecordCalendarComponentInstanceContext } from '@/object-record/record-calendar/states/contexts/RecordCalendarComponentInstanceContext';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID } from '@/action-menu/constants/ActionMenuDropdownClickOutsideId';
import { COMMAND_MENU_CLICK_OUTSIDE_ID } from '@/command-menu/constants/CommandMenuClickOutsideId';
import { MODAL_BACKDROP_CLICK_OUTSIDE_ID } from '@/ui/layout/modal/constants/ModalBackdropClickOutsideId';
import { PAGE_ACTION_CONTAINER_CLICK_OUTSIDE_ID } from '@/ui/layout/page/constants/PageActionContainerClickOutsideId';
import { RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-calendar/record-calendar-card/constants/RecordCalendarCardClickOutsideId';
import { LINK_CHIP_CLICK_OUTSIDE_ID } from 'twenty-ui/components';
import { useRecordCalendarSelection } from '@/object-record/record-calendar/states/selectors/useRecordCalendarSelection';
import { RECORD_CALENDAR_CLICK_OUTSIDE_LISTENER_ID } from '@/object-record/record-calendar/constants/RecordCalendarClickOutsideListenerId';
const StyledContainerContainer = styled.div`
display: flex;
@@ -20,6 +29,24 @@ export const RecordCalendar = () => {
RecordCalendarComponentInstanceContext,
);
const { resetRecordSelection } = useRecordCalendarSelection(recordCalendarId);
useListenClickOutside({
excludedClickOutsideIds: [
ACTION_MENU_DROPDOWN_CLICK_OUTSIDE_ID,
COMMAND_MENU_CLICK_OUTSIDE_ID,
MODAL_BACKDROP_CLICK_OUTSIDE_ID,
PAGE_ACTION_CONTAINER_CLICK_OUTSIDE_ID,
RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID,
LINK_CHIP_CLICK_OUTSIDE_ID,
],
listenerId: RECORD_CALENDAR_CLICK_OUTSIDE_LISTENER_ID,
refs: [],
callback: () => {
resetRecordSelection();
},
});
return (
<ScrollWrapper
componentInstanceId={`scroll-wrapper-record-calendar-${recordCalendarId}`}
@@ -0,0 +1 @@
export const RECORD_CALENDAR_CLICK_OUTSIDE_LISTENER_ID = 'record-calendar';
@@ -2,8 +2,11 @@ import { RecordCalendarCardCellEditModePortal } from '@/object-record/record-cal
import { RecordCalendarCardCellHoveredPortal } from '@/object-record/record-calendar/record-calendar-card/anchored-portal/components/RecordCalendarCardCellHoveredPortal';
import { RecordCalendarCardBody } from '@/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody';
import { RecordCalendarCardHeader } from '@/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader';
import { RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-calendar/record-calendar-card/constants/RecordCalendarCardClickOutsideId';
import { RecordCalendarCardComponentInstanceContext } from '@/object-record/record-calendar/record-calendar-card/states/contexts/RecordCalendarCardComponentInstanceContext';
import { isRecordCalendarCardSelectedComponentFamilyState } from '@/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState';
import { RecordCard } from '@/object-record/record-card/components/RecordCard';
import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import styled from '@emotion/styled';
import { AnimatedEaseInOut } from 'twenty-ui/utilities';
@@ -24,6 +27,10 @@ export const RecordCalendarCard = ({ recordId }: RecordCalendarCardProps) => {
const { currentView } = useGetCurrentViewOnly();
const isCompactModeActive = currentView?.isCompact ?? false;
const isCurrentCardSelected = useRecoilComponentFamilyValue(
isRecordCalendarCardSelectedComponentFamilyState,
recordId,
);
return (
<RecordCalendarCardComponentInstanceContext.Provider
@@ -32,7 +39,10 @@ export const RecordCalendarCard = ({ recordId }: RecordCalendarCardProps) => {
}}
>
<StyledContainer>
<StyledRecordCard>
<StyledRecordCard
data-selected={isCurrentCardSelected}
data-click-outside-id={RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID}
>
<RecordCalendarCardHeader recordId={recordId} />
<AnimatedEaseInOut isOpen={!isCompactModeActive} initial={false}>
<RecordCalendarCardBody
@@ -7,11 +7,13 @@ import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/u
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import { useRecoilComponentFamilyState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyState';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { ChipVariant } from 'twenty-ui/components';
import { Checkbox, CheckboxVariant } from 'twenty-ui/input';
import { isRecordCalendarCardSelectedComponentFamilyState } from '../states/isRecordCalendarCardSelectedComponentFamilyState';
const StyledCheckboxContainer = styled.div`
margin-left: auto;
@@ -46,6 +48,12 @@ export const RecordCalendarCardHeader = ({
const dragState = useRecordDragState('calendar', viewBarInstanceId);
const [isCurrentCardSelected, setIsCurrentCardSelected] =
useRecoilComponentFamilyState(
isRecordCalendarCardSelectedComponentFamilyState,
recordId,
);
const handleChipClick = () => {
if (dragState.isDragging) {
return;
@@ -75,8 +83,10 @@ export const RecordCalendarCardHeader = ({
<StopPropagationContainer>
<Checkbox
hoverable
checked={false}
onChange={() => {}}
checked={isCurrentCardSelected}
onChange={(value) => {
setIsCurrentCardSelected(value.target.checked);
}}
variant={CheckboxVariant.Secondary}
/>
</StopPropagationContainer>
@@ -0,0 +1 @@
export const RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID = 'record-calendar-card';
@@ -0,0 +1,9 @@
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
import { RecordCalendarComponentInstanceContext } from '../../states/contexts/RecordCalendarComponentInstanceContext';
export const isRecordCalendarCardSelectedComponentFamilyState =
createComponentFamilyState<boolean, string>({
key: 'isRecordCalendarCardSelectedComponentFamilyState',
defaultValue: false,
componentInstanceContext: RecordCalendarComponentInstanceContext,
});
@@ -0,0 +1,29 @@
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector';
import { RecordCalendarComponentInstanceContext } from '../contexts/RecordCalendarComponentInstanceContext';
import { isRecordCalendarCardSelectedComponentFamilyState } from '../../record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState';
export const recordCalendarSelectedRecordIdsComponentSelector =
createComponentSelector<string[]>({
key: 'recordCalendarSelectedRecordIdsSelector',
componentInstanceContext: RecordCalendarComponentInstanceContext,
get:
({ instanceId }) =>
({ get }) => {
const allRecordIds = get(
recordIndexAllRecordIdsComponentSelector.selectorFamily({
instanceId,
}),
);
return allRecordIds.filter(
(recordId) =>
get(
isRecordCalendarCardSelectedComponentFamilyState.atomFamily({
instanceId,
familyKey: recordId,
}),
) === true,
);
},
});
@@ -0,0 +1,62 @@
import { useRecoilCallback } from 'recoil';
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isRecordCalendarCardSelectedComponentFamilyState } from '../../record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState';
import { RecordCalendarComponentInstanceContext } from '../contexts/RecordCalendarComponentInstanceContext';
import { recordCalendarSelectedRecordIdsComponentSelector } from './recordCalendarSelectedRecordIdsComponentSelector';
export const useRecordCalendarSelection = (recordCalendarId?: string) => {
const instanceIdFromProps = useAvailableComponentInstanceIdOrThrow(
RecordCalendarComponentInstanceContext,
recordCalendarId,
);
const isRecordCalendarCardSelectedFamilyState =
useRecoilComponentCallbackState(
isRecordCalendarCardSelectedComponentFamilyState,
recordCalendarId,
);
const recordCalendarSelectedRecordIdsSelector =
useRecoilComponentCallbackState(
recordCalendarSelectedRecordIdsComponentSelector,
recordCalendarId,
);
const { closeDropdown } = useCloseDropdown();
const dropdownId = getActionMenuDropdownIdFromActionMenuId(
getActionMenuIdFromRecordIndexId(instanceIdFromProps),
);
const resetRecordSelection = useRecoilCallback(
({ snapshot, set }) =>
() => {
closeDropdown(dropdownId);
const recordIds = getSnapshotValue(
snapshot,
recordCalendarSelectedRecordIdsSelector,
);
for (const recordId of recordIds) {
set(isRecordCalendarCardSelectedFamilyState(recordId), false);
}
},
[
closeDropdown,
dropdownId,
recordCalendarSelectedRecordIdsSelector,
isRecordCalendarCardSelectedFamilyState,
],
);
return {
resetRecordSelection,
};
};