Improved activity editor re-renders (#4149)
* Refactor task count * Fixed show page rerender * Less rerenders and way better title and body UX * Finished breaking down activity editor subscriptions * Removed console.log * Last console.log * Fixed bugs and cleaned
This commit is contained in:
@ -1,28 +1,12 @@
|
||||
import { useRef } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { ActivityBodyEditor } from '@/activities/components/ActivityBodyEditor';
|
||||
import { ActivityBodyEffect } from '@/activities/components/ActivityBodyEffect';
|
||||
import { ActivityComments } from '@/activities/components/ActivityComments';
|
||||
import { ActivityEditorFields } from '@/activities/components/ActivityEditorFields';
|
||||
import { ActivityTitleEffect } from '@/activities/components/ActivityTitleEffect';
|
||||
import { ActivityTypeDropdown } from '@/activities/components/ActivityTypeDropdown';
|
||||
import { useDeleteActivityFromCache } from '@/activities/hooks/useDeleteActivityFromCache';
|
||||
import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity';
|
||||
import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/ActivityTargetsInlineCell';
|
||||
import { canCreateActivityState } from '@/activities/states/canCreateActivityState';
|
||||
import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState';
|
||||
import { isUpsertingActivityInDBState } from '@/activities/states/isCreatingActivityInDBState';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
||||
import {
|
||||
RecordUpdateHook,
|
||||
RecordUpdateHookParams,
|
||||
} from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
|
||||
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
|
||||
import { ActivityTitle } from './ActivityTitle';
|
||||
@ -60,152 +44,36 @@ const StyledTopContainer = styled.div`
|
||||
`;
|
||||
|
||||
type ActivityEditorProps = {
|
||||
activity: Activity;
|
||||
activityId: string;
|
||||
showComment?: boolean;
|
||||
fillTitleFromBody?: boolean;
|
||||
};
|
||||
|
||||
export const ActivityEditor = ({
|
||||
activity,
|
||||
activityId,
|
||||
showComment = true,
|
||||
fillTitleFromBody = false,
|
||||
}: ActivityEditorProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { useRegisterClickOutsideListenerCallback } = useClickOutsideListener(
|
||||
RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID,
|
||||
);
|
||||
|
||||
const { upsertActivity } = useUpsertActivity();
|
||||
const { deleteActivityFromCache } = useDeleteActivityFromCache();
|
||||
|
||||
const useUpsertOneActivityMutation: RecordUpdateHook = () => {
|
||||
const upsertActivityMutation = async ({
|
||||
variables,
|
||||
}: RecordUpdateHookParams) => {
|
||||
await upsertActivity({ activity, input: variables.updateOneRecordInput });
|
||||
};
|
||||
|
||||
return [upsertActivityMutation, { loading: false }];
|
||||
};
|
||||
|
||||
const { FieldContextProvider: DueAtFieldContextProvider } = useFieldContext({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectRecordId: activity.id,
|
||||
fieldMetadataName: 'dueAt',
|
||||
fieldPosition: 0,
|
||||
clearable: true,
|
||||
customUseUpdateOneObjectHook: useUpsertOneActivityMutation,
|
||||
});
|
||||
|
||||
const { FieldContextProvider: AssigneeFieldContextProvider } =
|
||||
useFieldContext({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectRecordId: activity.id,
|
||||
fieldMetadataName: 'assignee',
|
||||
fieldPosition: 1,
|
||||
clearable: true,
|
||||
customUseUpdateOneObjectHook: useUpsertOneActivityMutation,
|
||||
});
|
||||
|
||||
const [isActivityInCreateMode, setIsActivityInCreateMode] = useRecoilState(
|
||||
isActivityInCreateModeState,
|
||||
);
|
||||
|
||||
const [isUpsertingActivityInDB] = useRecoilState(
|
||||
isUpsertingActivityInDBState,
|
||||
);
|
||||
|
||||
const [canCreateActivity] = useRecoilState(canCreateActivityState);
|
||||
|
||||
const [activityFromStore] = useRecoilState(
|
||||
recordStoreFamilyState(activity.id),
|
||||
);
|
||||
|
||||
const { FieldContextProvider: ActivityTargetsContextProvider } =
|
||||
useFieldContext({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectRecordId: activity?.id ?? '',
|
||||
fieldMetadataName: 'activityTargets',
|
||||
fieldPosition: 2,
|
||||
});
|
||||
|
||||
useRegisterClickOutsideListenerCallback({
|
||||
callbackId: 'activity-editor',
|
||||
callbackFunction: () => {
|
||||
if (isUpsertingActivityInDB || !activityFromStore) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isActivityInCreateMode) {
|
||||
if (canCreateActivity) {
|
||||
upsertActivity({
|
||||
activity,
|
||||
input: {
|
||||
title: activityFromStore.title,
|
||||
body: activityFromStore.body,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
deleteActivityFromCache(activity);
|
||||
}
|
||||
|
||||
setIsActivityInCreateMode(false);
|
||||
} else {
|
||||
if (
|
||||
activityFromStore.title !== activity.title ||
|
||||
activityFromStore.body !== activity.body
|
||||
) {
|
||||
upsertActivity({
|
||||
activity,
|
||||
input: {
|
||||
title: activityFromStore.title,
|
||||
body: activityFromStore.body,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (!activity) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledContainer ref={containerRef}>
|
||||
<StyledUpperPartContainer>
|
||||
<StyledTopContainer>
|
||||
<ActivityTypeDropdown activity={activity} />
|
||||
<ActivityTitle activity={activity} />
|
||||
<PropertyBox>
|
||||
{activity.type === 'Task' &&
|
||||
DueAtFieldContextProvider &&
|
||||
AssigneeFieldContextProvider && (
|
||||
<>
|
||||
<DueAtFieldContextProvider>
|
||||
<RecordInlineCell />
|
||||
</DueAtFieldContextProvider>
|
||||
<AssigneeFieldContextProvider>
|
||||
<RecordInlineCell />
|
||||
</AssigneeFieldContextProvider>
|
||||
</>
|
||||
)}
|
||||
{ActivityTargetsContextProvider && (
|
||||
<ActivityTargetsContextProvider>
|
||||
<ActivityTargetsInlineCell activity={activity} />
|
||||
</ActivityTargetsContextProvider>
|
||||
)}
|
||||
</PropertyBox>
|
||||
<ActivityTypeDropdown activityId={activityId} />
|
||||
<ActivityTitleEffect activityId={activityId} />
|
||||
<ActivityTitle activityId={activityId} />
|
||||
<ActivityEditorFields activityId={activityId} />
|
||||
</StyledTopContainer>
|
||||
</StyledUpperPartContainer>
|
||||
<ActivityBodyEffect activityId={activityId} />
|
||||
<ActivityBodyEditor
|
||||
activity={activity}
|
||||
activityId={activityId}
|
||||
fillTitleFromBody={fillTitleFromBody}
|
||||
/>
|
||||
{showComment && (
|
||||
<ActivityComments
|
||||
activity={activity}
|
||||
activityId={activityId}
|
||||
scrollableContainerRef={containerRef}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user