@ -5,7 +5,7 @@ import { Comment as CommentType } from '@/activities/types/Comment';
|
|||||||
import { CommentHeader } from './CommentHeader';
|
import { CommentHeader } from './CommentHeader';
|
||||||
|
|
||||||
type CommentProps = {
|
type CommentProps = {
|
||||||
comment: Omit<CommentType, 'activityId'>;
|
comment: CommentType;
|
||||||
actionBar?: React.ReactNode;
|
actionBar?: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -8,11 +8,6 @@ import {
|
|||||||
beautifyPastDateRelativeToNow,
|
beautifyPastDateRelativeToNow,
|
||||||
} from '~/utils/date-utils';
|
} from '~/utils/date-utils';
|
||||||
|
|
||||||
type CommentHeaderProps = {
|
|
||||||
comment: Pick<Comment, 'id' | 'author' | 'createdAt'>;
|
|
||||||
actionBar?: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -61,6 +56,11 @@ const StyledTooltip = styled(Tooltip)`
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
type CommentHeaderProps = {
|
||||||
|
comment: Pick<Comment, 'id' | 'author' | 'createdAt'>;
|
||||||
|
actionBar?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => {
|
export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => {
|
||||||
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(comment.createdAt);
|
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(comment.createdAt);
|
||||||
const exactCreatedAt = beautifyExactDateTime(comment.createdAt);
|
const exactCreatedAt = beautifyExactDateTime(comment.createdAt);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { Comment } from '@/activities/types/Comment';
|
|||||||
|
|
||||||
export const mockComment: Pick<
|
export const mockComment: Pick<
|
||||||
Comment,
|
Comment,
|
||||||
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt'
|
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt' | 'activityId'
|
||||||
> = {
|
> = {
|
||||||
id: 'fake_comment_1_uuid',
|
id: 'fake_comment_1_uuid',
|
||||||
body: 'Hello, this is a comment.',
|
body: 'Hello, this is a comment.',
|
||||||
@ -18,11 +18,12 @@ export const mockComment: Pick<
|
|||||||
},
|
},
|
||||||
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
|
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
|
||||||
updatedAt: DateTime.fromFormat('2021-03-13', 'yyyy-MM-dd').toISO() ?? '',
|
updatedAt: DateTime.fromFormat('2021-03-13', 'yyyy-MM-dd').toISO() ?? '',
|
||||||
|
activityId: 'fake_activity_1_uuid',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockCommentWithLongValues: Pick<
|
export const mockCommentWithLongValues: Pick<
|
||||||
Comment,
|
Comment,
|
||||||
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt'
|
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt' | 'activityId'
|
||||||
> = {
|
> = {
|
||||||
id: 'fake_comment_2_uuid',
|
id: 'fake_comment_2_uuid',
|
||||||
body: 'Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment.',
|
body: 'Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment.',
|
||||||
@ -36,4 +37,5 @@ export const mockCommentWithLongValues: Pick<
|
|||||||
},
|
},
|
||||||
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
|
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
|
||||||
updatedAt: DateTime.fromFormat('2021-03-13', 'yyyy-MM-dd').toISO() ?? '',
|
updatedAt: DateTime.fromFormat('2021-03-13', 'yyyy-MM-dd').toISO() ?? '',
|
||||||
|
activityId: 'fake_activity_1_uuid',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export const ActivityBodyEditor = ({
|
|||||||
}: ActivityBodyEditorProps) => {
|
}: ActivityBodyEditorProps) => {
|
||||||
const [body, setBody] = useState<string | null>(null);
|
const [body, setBody] = useState<string | null>(null);
|
||||||
const { updateOneObject } = useUpdateOneObjectRecord({
|
const { updateOneObject } = useUpdateOneObjectRecord({
|
||||||
objectNameSingular: 'Activity',
|
objectNameSingular: 'activity',
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -6,21 +6,15 @@ import { v4 } from 'uuid';
|
|||||||
import { Comment } from '@/activities/comment/Comment';
|
import { Comment } from '@/activities/comment/Comment';
|
||||||
import { Activity } from '@/activities/types/Activity';
|
import { Activity } from '@/activities/types/Activity';
|
||||||
import { Comment as CommentType } from '@/activities/types/Comment';
|
import { Comment as CommentType } from '@/activities/types/Comment';
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
|
import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
|
||||||
|
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
||||||
import {
|
import {
|
||||||
AutosizeTextInput,
|
AutosizeTextInput,
|
||||||
AutosizeTextInputVariant,
|
AutosizeTextInputVariant,
|
||||||
} from '@/ui/input/components/AutosizeTextInput';
|
} from '@/ui/input/components/AutosizeTextInput';
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
|
|
||||||
type ActivityCommentsProps = {
|
|
||||||
activity: Pick<Activity, 'id'> & {
|
|
||||||
comments: Array<CommentType>;
|
|
||||||
};
|
|
||||||
scrollableContainerRef: React.RefObject<HTMLDivElement>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledThreadItemListContainer = styled.div`
|
const StyledThreadItemListContainer = styled.div`
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
@ -57,16 +51,31 @@ const StyledThreadCommentTitle = styled.div`
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
type ActivityCommentsProps = {
|
||||||
|
activity: Pick<Activity, 'id'>;
|
||||||
|
scrollableContainerRef: React.RefObject<HTMLDivElement>;
|
||||||
|
};
|
||||||
|
|
||||||
export const ActivityComments = ({
|
export const ActivityComments = ({
|
||||||
activity,
|
activity,
|
||||||
scrollableContainerRef,
|
scrollableContainerRef,
|
||||||
}: ActivityCommentsProps) => {
|
}: ActivityCommentsProps) => {
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
|
||||||
const { createOneObject } = useCreateOneObjectRecord({
|
const { createOneObject } = useCreateOneObjectRecord({
|
||||||
objectNameSingular: 'comment',
|
objectNameSingular: 'comment',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!currentUser) {
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
|
|
||||||
|
const { objects: comments } = useFindManyObjectRecords({
|
||||||
|
objectNamePlural: 'comments',
|
||||||
|
filter: {
|
||||||
|
activityId: {
|
||||||
|
eq: activity?.id ?? '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!currentWorkspaceMember) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +85,10 @@ export const ActivityComments = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
createOneObject?.({
|
createOneObject?.({
|
||||||
commentId: v4(),
|
id: v4(),
|
||||||
authorId: currentUser?.id ?? '',
|
authorId: currentWorkspaceMember?.id ?? '',
|
||||||
activityId: activity?.id ?? '',
|
activityId: activity?.id ?? '',
|
||||||
commentText: commentText,
|
body: commentText,
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -93,26 +102,28 @@ export const ActivityComments = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('asd', { activity, comments });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activity?.comments.length > 0 && (
|
{comments.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<StyledThreadItemListContainer>
|
<StyledThreadItemListContainer>
|
||||||
<StyledThreadCommentTitle>Comments</StyledThreadCommentTitle>
|
<StyledThreadCommentTitle>Comments</StyledThreadCommentTitle>
|
||||||
{activity?.comments?.map((comment) => (
|
{comments?.map((comment) => (
|
||||||
<Comment key={comment.id} comment={comment} />
|
<Comment key={comment.id} comment={comment as CommentType} />
|
||||||
))}
|
))}
|
||||||
</StyledThreadItemListContainer>
|
</StyledThreadItemListContainer>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<StyledCommentActionBar>
|
<StyledCommentActionBar>
|
||||||
{currentUser && (
|
{currentWorkspaceMember && (
|
||||||
<AutosizeTextInput
|
<AutosizeTextInput
|
||||||
onValidate={handleSendComment}
|
onValidate={handleSendComment}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
variant={AutosizeTextInputVariant.Button}
|
variant={AutosizeTextInputVariant.Button}
|
||||||
placeholder={activity?.comments.length > 0 ? 'Reply...' : undefined}
|
placeholder={comments.length > 0 ? 'Reply...' : undefined}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledCommentActionBar>
|
</StyledCommentActionBar>
|
||||||
|
|||||||
@ -13,8 +13,6 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
|||||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||||
import { debounce } from '~/utils/debounce';
|
import { debounce } from '~/utils/debounce';
|
||||||
|
|
||||||
import { ActivityRelationEditableField } from '../editable-fields/components/ActivityRelationEditableField';
|
|
||||||
|
|
||||||
import { ActivityTitle } from './ActivityTitle';
|
import { ActivityTitle } from './ActivityTitle';
|
||||||
|
|
||||||
import '@blocknote/core/style.css';
|
import '@blocknote/core/style.css';
|
||||||
@ -75,6 +73,10 @@ export const ActivityEditor = ({
|
|||||||
const [hasUserManuallySetTitle, setHasUserManuallySetTitle] =
|
const [hasUserManuallySetTitle, setHasUserManuallySetTitle] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
activity,
|
||||||
|
});
|
||||||
|
|
||||||
const [title, setTitle] = useState<string | null>(activity.title ?? '');
|
const [title, setTitle] = useState<string | null>(activity.title ?? '');
|
||||||
const [completedAt, setCompletedAt] = useState<string | null>(
|
const [completedAt, setCompletedAt] = useState<string | null>(
|
||||||
activity.completedAt ?? '',
|
activity.completedAt ?? '',
|
||||||
@ -149,7 +151,7 @@ export const ActivityEditor = ({
|
|||||||
</RecoilScope> */}
|
</RecoilScope> */}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<ActivityRelationEditableField activity={activity} />
|
{/* <ActivityRelationEditableField activity={activity} /> */}
|
||||||
</PropertyBox>
|
</PropertyBox>
|
||||||
</StyledTopContainer>
|
</StyledTopContainer>
|
||||||
<ActivityBodyEditor
|
<ActivityBodyEditor
|
||||||
@ -159,10 +161,7 @@ export const ActivityEditor = ({
|
|||||||
</StyledUpperPartContainer>
|
</StyledUpperPartContainer>
|
||||||
{showComment && (
|
{showComment && (
|
||||||
<ActivityComments
|
<ActivityComments
|
||||||
activity={{
|
activity={activity}
|
||||||
id: activity.id,
|
|
||||||
comments: activity.comments ?? [],
|
|
||||||
}}
|
|
||||||
scrollableContainerRef={containerRef}
|
scrollableContainerRef={containerRef}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
|
||||||
import { CompanyChip } from '@/companies/components/CompanyChip';
|
import { CompanyChip } from '@/companies/components/CompanyChip';
|
||||||
import { Company } from '@/companies/types/Company';
|
|
||||||
import { PersonChip } from '@/people/components/PersonChip';
|
import { PersonChip } from '@/people/components/PersonChip';
|
||||||
import { Person } from '@/people/types/Person';
|
|
||||||
import { getLogoUrlFromDomainName } from '~/utils';
|
import { getLogoUrlFromDomainName } from '~/utils';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -13,23 +10,15 @@ const StyledContainer = styled.div`
|
|||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ActivityTargetChips = ({
|
// TODO: fix edges pagination formatting on n+N
|
||||||
targets,
|
export const ActivityTargetChips = ({ targets }: { targets?: any }) => {
|
||||||
}: {
|
|
||||||
targets?: Array<
|
|
||||||
Pick<ActivityTarget, 'id'> & {
|
|
||||||
person?: Pick<Person, 'id' | 'name' | 'avatarUrl'> | null;
|
|
||||||
company?: Pick<Company, 'id' | 'domainName' | 'name'> | null;
|
|
||||||
}
|
|
||||||
> | null;
|
|
||||||
}) => {
|
|
||||||
if (!targets) {
|
if (!targets) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
{targets.map(({ company, person }) => {
|
{targets?.edges?.map(({ company, person }: any) => {
|
||||||
if (company) {
|
if (company) {
|
||||||
return (
|
return (
|
||||||
<CompanyChip
|
<CompanyChip
|
||||||
|
|||||||
@ -1,21 +1,52 @@
|
|||||||
import { Note } from '@/activities/types/Note';
|
import { Note } from '@/activities/types/Note';
|
||||||
|
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition';
|
||||||
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
||||||
|
|
||||||
import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity';
|
import { ActivityTargetableEntity } from '../../types/ActivityTargetableEntity';
|
||||||
|
|
||||||
export const useNotes = (entity: ActivityTargetableEntity) => {
|
export const useNotes = (entity: ActivityTargetableEntity) => {
|
||||||
const { objects: notes } = useFindManyObjectRecords({
|
const { objects: activityTargets } = useFindManyObjectRecords({
|
||||||
objectNamePlural: 'activities',
|
objectNamePlural: 'activityTargets',
|
||||||
filter: {
|
filter: {
|
||||||
type: { equals: 'None' },
|
[entity.type === 'Company' ? 'companyId' : 'personId']: { eq: entity.id },
|
||||||
activityTargets: {
|
},
|
||||||
some: {
|
});
|
||||||
OR: [
|
|
||||||
{ companyId: { equals: entity.id } },
|
const { objectMetadataItem: activityObjectMetadataItem } =
|
||||||
{ personId: { equals: entity.id } },
|
useObjectMetadataItem({
|
||||||
],
|
objectNameSingular: 'activity',
|
||||||
},
|
});
|
||||||
},
|
|
||||||
|
const { registerOptimisticEffect } = useOptimisticEffect({
|
||||||
|
objectNameSingular: activityObjectMetadataItem?.nameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
id: {
|
||||||
|
in: activityTargets?.map((activityTarget) => activityTarget.activityId),
|
||||||
|
},
|
||||||
|
type: { eq: 'Note' },
|
||||||
|
};
|
||||||
|
const orderBy = {
|
||||||
|
createdAt: 'AscNullsFirst',
|
||||||
|
};
|
||||||
|
|
||||||
|
const { objects: notes } = useFindManyObjectRecords({
|
||||||
|
skip: !activityTargets?.length,
|
||||||
|
objectNamePlural: 'activities',
|
||||||
|
filter,
|
||||||
|
orderBy,
|
||||||
|
onCompleted: () => {
|
||||||
|
if (activityObjectMetadataItem) {
|
||||||
|
registerOptimisticEffect({
|
||||||
|
variables: { orderBy, filter },
|
||||||
|
definition: getRecordOptimisticEffectDefinition({
|
||||||
|
objectMetadataItem: activityObjectMetadataItem,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export const RightDrawerActivity = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { object: activity } = useFindOneObjectRecord({
|
const { object: activity } = useFindOneObjectRecord({
|
||||||
objectNameSingular: 'activityId',
|
objectNameSingular: 'activity',
|
||||||
objectRecordId: activityId,
|
objectRecordId: activityId,
|
||||||
skip: !activityId,
|
skip: !activityId,
|
||||||
onCompleted: (activity: Activity) => {
|
onCompleted: (activity: Activity) => {
|
||||||
|
|||||||
@ -2,55 +2,108 @@ import { DateTime } from 'luxon';
|
|||||||
|
|
||||||
import { Activity } from '@/activities/types/Activity';
|
import { Activity } from '@/activities/types/Activity';
|
||||||
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
|
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
|
||||||
|
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { getRecordOptimisticEffectDefinition } from '@/object-record/graphql/optimistic-effect-definition/getRecordOptimisticEffectDefinition';
|
||||||
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
||||||
import { useFilter } from '@/ui/object/object-filter-dropdown/hooks/useFilter';
|
import { useFilter } from '@/ui/object/object-filter-dropdown/hooks/useFilter';
|
||||||
import { turnFiltersIntoWhereClauseV2 } from '@/ui/object/object-filter-dropdown/utils/turnFiltersIntoWhereClauseV2';
|
|
||||||
import { parseDate } from '~/utils/date-utils';
|
import { parseDate } from '~/utils/date-utils';
|
||||||
|
|
||||||
export const useTasks = (entity?: ActivityTargetableEntity) => {
|
export const useTasks = (entity?: ActivityTargetableEntity) => {
|
||||||
const { selectedFilter } = useFilter();
|
const { selectedFilter } = useFilter();
|
||||||
|
|
||||||
const whereFilters = entity
|
const { objects: activityTargets } = useFindManyObjectRecords({
|
||||||
? {
|
objectNamePlural: 'activityTargets',
|
||||||
activityTargets: {
|
filter: {
|
||||||
some: {
|
[entity?.type === 'Company' ? 'companyId' : 'personId']: {
|
||||||
OR: [
|
eq: entity?.id,
|
||||||
{ companyId: { equals: entity.id } },
|
},
|
||||||
{ personId: { equals: entity.id } },
|
},
|
||||||
],
|
});
|
||||||
},
|
|
||||||
},
|
const { objectMetadataItem: activityObjectMetadataItem } =
|
||||||
}
|
useObjectMetadataItem({
|
||||||
: Object.assign({}, turnFiltersIntoWhereClauseV2([], []));
|
objectNameSingular: 'activity',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { registerOptimisticEffect } = useOptimisticEffect({
|
||||||
|
objectNameSingular: activityObjectMetadataItem?.nameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
const { objects: completeTasksData } = useFindManyObjectRecords({
|
const { objects: completeTasksData } = useFindManyObjectRecords({
|
||||||
objectNamePlural: 'activities',
|
objectNamePlural: 'activities',
|
||||||
skip: !entity && !selectedFilter,
|
skip: !entity && !selectedFilter,
|
||||||
filter: {
|
filter: {
|
||||||
type: { equals: 'Task' },
|
|
||||||
completedAt: { is: 'NOT_NULL' },
|
completedAt: { is: 'NOT_NULL' },
|
||||||
...whereFilters,
|
id: {
|
||||||
},
|
in: activityTargets?.map((activityTarget) => activityTarget.activityId),
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
createdAt: 'AscNullIsFirst',
|
|
||||||
},
|
},
|
||||||
],
|
type: { eq: 'Task' },
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'DescNullsFirst',
|
||||||
|
},
|
||||||
|
onCompleted: () => {
|
||||||
|
if (activityObjectMetadataItem) {
|
||||||
|
registerOptimisticEffect({
|
||||||
|
variables: {
|
||||||
|
filter: {
|
||||||
|
completedAt: { is: 'NOT_NULL' },
|
||||||
|
id: {
|
||||||
|
in: activityTargets?.map(
|
||||||
|
(activityTarget) => activityTarget.activityId,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
type: { eq: 'Task' },
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'DescNullsFirst',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
definition: getRecordOptimisticEffectDefinition({
|
||||||
|
objectMetadataItem: activityObjectMetadataItem,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { objects: incompleteTaskData } = useFindManyObjectRecords({
|
const { objects: incompleteTaskData } = useFindManyObjectRecords({
|
||||||
objectNamePlural: 'activities',
|
objectNamePlural: 'activities',
|
||||||
skip: !entity && !selectedFilter,
|
skip: !entity && !selectedFilter,
|
||||||
filter: {
|
filter: {
|
||||||
type: { equals: 'Task' },
|
|
||||||
completedAt: { is: 'NULL' },
|
completedAt: { is: 'NULL' },
|
||||||
...whereFilters,
|
id: {
|
||||||
},
|
in: activityTargets?.map((activityTarget) => activityTarget.activityId),
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
createdAt: 'DescNullIsFirst',
|
|
||||||
},
|
},
|
||||||
],
|
type: { eq: 'Task' },
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'DescNullsFirst',
|
||||||
|
},
|
||||||
|
onCompleted: () => {
|
||||||
|
if (activityObjectMetadataItem) {
|
||||||
|
registerOptimisticEffect({
|
||||||
|
variables: {
|
||||||
|
filter: {
|
||||||
|
completedAt: { is: 'NULL' },
|
||||||
|
id: {
|
||||||
|
in: activityTargets?.map(
|
||||||
|
(activityTarget) => activityTarget.activityId,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
type: { eq: 'Task' },
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'DescNullsFirst',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
definition: getRecordOptimisticEffectDefinition({
|
||||||
|
objectMetadataItem: activityObjectMetadataItem,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const todayOrPreviousTasks = incompleteTaskData?.filter((task) => {
|
const todayOrPreviousTasks = incompleteTaskData?.filter((task) => {
|
||||||
|
|||||||
@ -51,10 +51,7 @@ export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => {
|
|||||||
const { objects: activityTargets, loading } = useFindManyObjectRecords({
|
const { objects: activityTargets, loading } = useFindManyObjectRecords({
|
||||||
objectNamePlural: 'activityTargets',
|
objectNamePlural: 'activityTargets',
|
||||||
filter: {
|
filter: {
|
||||||
or: {
|
[entity.type === 'Company' ? 'companyId' : 'personId']: { eq: entity.id },
|
||||||
companyId: { eq: entity.id },
|
|
||||||
personId: { eq: entity.id },
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -62,7 +59,9 @@ export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => {
|
|||||||
skip: !activityTargets?.length,
|
skip: !activityTargets?.length,
|
||||||
objectNamePlural: 'activities',
|
objectNamePlural: 'activities',
|
||||||
filter: {
|
filter: {
|
||||||
activityTargets: { in: activityTargets?.map((at) => at.id) },
|
id: {
|
||||||
|
in: activityTargets?.map((activityTarget) => activityTarget.activityId),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
createdAt: 'AscNullsFirst',
|
createdAt: 'AscNullsFirst',
|
||||||
|
|||||||
@ -24,26 +24,25 @@ export const useCreateOneObjectRecord = <T>({
|
|||||||
// TODO: type this with a minimal type at least with Record<string, any>
|
// TODO: type this with a minimal type at least with Record<string, any>
|
||||||
const [mutate] = useMutation(createOneMutation);
|
const [mutate] = useMutation(createOneMutation);
|
||||||
|
|
||||||
const createOneObject =
|
const createOneObject = async (input: Record<string, any>) => {
|
||||||
objectNameSingular && foundObjectMetadataItem
|
if (!foundObjectMetadataItem || !objectNameSingular) {
|
||||||
? async (input: Record<string, any>) => {
|
return null;
|
||||||
const createdObject = await mutate({
|
}
|
||||||
variables: {
|
|
||||||
input: { ...input, id: v4() },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
triggerOptimisticEffects(
|
const createdObject = await mutate({
|
||||||
`${capitalize(foundObjectMetadataItem.nameSingular)}Edge`,
|
variables: {
|
||||||
createdObject.data[
|
input: { ...input, id: v4() },
|
||||||
`create${capitalize(foundObjectMetadataItem.nameSingular)}`
|
},
|
||||||
],
|
});
|
||||||
);
|
|
||||||
return createdObject.data[
|
triggerOptimisticEffects(
|
||||||
`create${capitalize(objectNameSingular)}`
|
`${capitalize(foundObjectMetadataItem.nameSingular)}Edge`,
|
||||||
] as T;
|
createdObject.data[
|
||||||
}
|
`create${capitalize(foundObjectMetadataItem.nameSingular)}`
|
||||||
: undefined;
|
],
|
||||||
|
);
|
||||||
|
return createdObject.data[`create${capitalize(objectNameSingular)}`] as T;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createOneObject,
|
createOneObject,
|
||||||
|
|||||||
@ -23,20 +23,18 @@ export const useDeleteOneObjectRecord = <T>({
|
|||||||
|
|
||||||
const deleteOneObject = useCallback(
|
const deleteOneObject = useCallback(
|
||||||
async (idToDelete: string) => {
|
async (idToDelete: string) => {
|
||||||
if (objectNameSingular && foundObjectMetadataItem) {
|
if (!foundObjectMetadataItem || !objectNameSingular) {
|
||||||
const deletedObject = await mutate({
|
return null;
|
||||||
variables: {
|
|
||||||
idToDelete,
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(findManyQuery) ?? ''],
|
|
||||||
});
|
|
||||||
|
|
||||||
return deletedObject.data[
|
|
||||||
`create${capitalize(objectNameSingular)}`
|
|
||||||
] as T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
const deletedObject = await mutate({
|
||||||
|
variables: {
|
||||||
|
idToDelete,
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(findManyQuery) ?? ''],
|
||||||
|
});
|
||||||
|
|
||||||
|
return deletedObject.data[`create${capitalize(objectNameSingular)}`] as T;
|
||||||
},
|
},
|
||||||
[foundObjectMetadataItem, mutate, objectNameSingular, findManyQuery],
|
[foundObjectMetadataItem, mutate, objectNameSingular, findManyQuery],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -48,20 +48,17 @@ export const useFindManyObjectRecords = <
|
|||||||
isFetchingMoreObjectsFamilyState(objectNamePlural),
|
isFetchingMoreObjectsFamilyState(objectNamePlural),
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const { objectMetadataItem, objectNotFoundInMetadata, findManyQuery } =
|
||||||
objectMetadataItem: foundObjectMetadataItem,
|
useObjectMetadataItem({
|
||||||
objectNotFoundInMetadata,
|
objectNamePlural,
|
||||||
findManyQuery,
|
});
|
||||||
} = useObjectMetadataItem({
|
|
||||||
objectNamePlural,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { enqueueSnackBar } = useSnackBar();
|
const { enqueueSnackBar } = useSnackBar();
|
||||||
|
|
||||||
const { data, loading, error, fetchMore } = useQuery<
|
const { data, loading, error, fetchMore } = useQuery<
|
||||||
PaginatedObjectType<ObjectType>
|
PaginatedObjectType<ObjectType>
|
||||||
>(findManyQuery, {
|
>(findManyQuery, {
|
||||||
skip: skip || !foundObjectMetadataItem || !objectNamePlural,
|
skip: skip || !objectMetadataItem || !objectNamePlural,
|
||||||
variables: {
|
variables: {
|
||||||
filter: filter ?? {},
|
filter: filter ?? {},
|
||||||
orderBy: orderBy ?? {},
|
orderBy: orderBy ?? {},
|
||||||
@ -130,7 +127,7 @@ export const useFindManyObjectRecords = <
|
|||||||
return Object.assign({}, prev, {
|
return Object.assign({}, prev, {
|
||||||
[objectNamePlural]: {
|
[objectNamePlural]: {
|
||||||
__typename: `${capitalize(
|
__typename: `${capitalize(
|
||||||
foundObjectMetadataItem?.nameSingular ?? '',
|
objectMetadataItem?.nameSingular ?? '',
|
||||||
)}Connection`,
|
)}Connection`,
|
||||||
edges: newEdges,
|
edges: newEdges,
|
||||||
pageInfo: fetchMoreResult?.[objectNamePlural].pageInfo,
|
pageInfo: fetchMoreResult?.[objectNamePlural].pageInfo,
|
||||||
@ -156,7 +153,7 @@ export const useFindManyObjectRecords = <
|
|||||||
fetchMore,
|
fetchMore,
|
||||||
filter,
|
filter,
|
||||||
orderBy,
|
orderBy,
|
||||||
foundObjectMetadataItem,
|
objectMetadataItem,
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
setIsFetchingMoreObjects,
|
setIsFetchingMoreObjects,
|
||||||
enqueueSnackBar,
|
enqueueSnackBar,
|
||||||
@ -174,6 +171,7 @@ export const useFindManyObjectRecords = <
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
objectMetadataItem,
|
||||||
objects,
|
objects,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
|
|||||||
@ -18,29 +18,28 @@ export const useUpdateOneObjectRecord = <T>({
|
|||||||
// TODO: type this with a minimal type at least with Record<string, any>
|
// TODO: type this with a minimal type at least with Record<string, any>
|
||||||
const [mutate] = useMutation(updateOneMutation);
|
const [mutate] = useMutation(updateOneMutation);
|
||||||
|
|
||||||
const updateOneObject =
|
const updateOneObject = async ({
|
||||||
objectNameSingular && foundObjectMetadataItem
|
idToUpdate,
|
||||||
? async ({
|
input,
|
||||||
idToUpdate,
|
}: {
|
||||||
input,
|
idToUpdate: string;
|
||||||
}: {
|
input: Record<string, any>;
|
||||||
idToUpdate: string;
|
}) => {
|
||||||
input: Record<string, any>;
|
if (!foundObjectMetadataItem || !objectNameSingular) {
|
||||||
}) => {
|
return null;
|
||||||
const updatedObject = await mutate({
|
}
|
||||||
variables: {
|
|
||||||
idToUpdate: idToUpdate,
|
|
||||||
input: {
|
|
||||||
...input,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return updatedObject.data[
|
const updatedObject = await mutate({
|
||||||
`update${capitalize(objectNameSingular)}`
|
variables: {
|
||||||
] as T;
|
idToUpdate: idToUpdate,
|
||||||
}
|
input: {
|
||||||
: undefined;
|
...input,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return updatedObject.data[`update${capitalize(objectNameSingular)}`] as T;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updateOneObject,
|
updateOneObject,
|
||||||
|
|||||||
@ -259,7 +259,7 @@ export const seedActivityFieldMetadata = async (
|
|||||||
workspaceId: SeedWorkspaceId,
|
workspaceId: SeedWorkspaceId,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: 'Comments',
|
name: 'comments',
|
||||||
label: 'Comments',
|
label: 'Comments',
|
||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Activity comments',
|
description: 'Activity comments',
|
||||||
|
|||||||
@ -130,7 +130,7 @@ export const seedCommentFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Comment author',
|
description: 'Comment author',
|
||||||
icon: 'IconCircleUser',
|
icon: 'IconCircleUser',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: false,
|
isSystem: false,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
@ -146,7 +146,7 @@ export const seedCommentFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Comment author id foreign key',
|
description: 'Comment author id foreign key',
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
@ -162,7 +162,7 @@ export const seedCommentFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Comment activity',
|
description: 'Comment activity',
|
||||||
icon: 'IconNotes',
|
icon: 'IconNotes',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: false,
|
isSystem: false,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
@ -178,7 +178,7 @@ export const seedCommentFieldMetadata = async (
|
|||||||
targetColumnMap: {},
|
targetColumnMap: {},
|
||||||
description: 'Activity id foreign key',
|
description: 'Activity id foreign key',
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
defaultValue: undefined,
|
defaultValue: undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -37,7 +37,7 @@ const commentMetadata = {
|
|||||||
},
|
},
|
||||||
description: 'Comment author',
|
description: 'Comment author',
|
||||||
icon: 'IconCircleUser',
|
icon: 'IconCircleUser',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isCustom: false,
|
isCustom: false,
|
||||||
@ -50,7 +50,7 @@ const commentMetadata = {
|
|||||||
},
|
},
|
||||||
description: 'Comment activity',
|
description: 'Comment activity',
|
||||||
icon: 'IconNotes',
|
icon: 'IconNotes',
|
||||||
isNullable: false,
|
isNullable: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user