Migrate activities (#2545)

* Start

* Migrate activities to flexible schema
This commit is contained in:
Charles Bochet
2023-11-16 17:10:22 +01:00
committed by GitHub
parent 7da18a13e8
commit dee38bb901
69 changed files with 518 additions and 1479 deletions

View File

@ -181,7 +181,10 @@ export const PageChangeEffect = () => {
)?.params.id; )?.params.id;
const entity = !!companyId const entity = !!companyId
? { id: companyId, type: ActivityTargetableEntityType.Company } ? {
id: companyId,
type: 'Company' as ActivityTargetableEntityType,
}
: undefined; : undefined;
addToCommandMenu([ addToCommandMenu([
@ -192,7 +195,7 @@ export const PageChangeEffect = () => {
Icon: IconCheckbox, Icon: IconCheckbox,
onCommandClick: () => onCommandClick: () =>
openCreateActivity({ openCreateActivity({
type: ActivityType.Task, type: 'Task',
targetableEntities: entity ? [entity] : undefined, targetableEntities: entity ? [entity] : undefined,
}), }),
}, },
@ -215,7 +218,7 @@ export const PageChangeEffect = () => {
?.params.id; ?.params.id;
const entity = !!personId const entity = !!personId
? { id: personId, type: ActivityTargetableEntityType.Person } ? { id: personId, type: 'Person' as ActivityTargetableEntityType }
: undefined; : undefined;
addToCommandMenu([ addToCommandMenu([

View File

@ -656,6 +656,11 @@ export type BoolFilter = {
not?: InputMaybe<NestedBoolFilter>; not?: InputMaybe<NestedBoolFilter>;
}; };
export type BooleanFieldComparison = {
is?: InputMaybe<Scalars['Boolean']>;
isNot?: InputMaybe<Scalars['Boolean']>;
};
export type ClientConfig = { export type ClientConfig = {
__typename?: 'ClientConfig'; __typename?: 'ClientConfig';
authProviders: AuthProviders; authProviders: AuthProviders;
@ -1315,6 +1320,7 @@ export type FieldDeleteResponse = {
isActive?: Maybe<Scalars['Boolean']>; isActive?: Maybe<Scalars['Boolean']>;
isCustom?: Maybe<Scalars['Boolean']>; isCustom?: Maybe<Scalars['Boolean']>;
isNullable?: Maybe<Scalars['Boolean']>; isNullable?: Maybe<Scalars['Boolean']>;
isSystem?: Maybe<Scalars['Boolean']>;
label?: Maybe<Scalars['String']>; label?: Maybe<Scalars['String']>;
name?: Maybe<Scalars['String']>; name?: Maybe<Scalars['String']>;
/** @deprecated Use label name instead */ /** @deprecated Use label name instead */
@ -1357,6 +1363,23 @@ export type FloatFilter = {
notIn?: InputMaybe<Array<Scalars['Float']>>; notIn?: InputMaybe<Array<Scalars['Float']>>;
}; };
export type IdFilterComparison = {
eq?: InputMaybe<Scalars['ID']>;
gt?: InputMaybe<Scalars['ID']>;
gte?: InputMaybe<Scalars['ID']>;
iLike?: InputMaybe<Scalars['ID']>;
in?: InputMaybe<Array<Scalars['ID']>>;
is?: InputMaybe<Scalars['Boolean']>;
isNot?: InputMaybe<Scalars['Boolean']>;
like?: InputMaybe<Scalars['ID']>;
lt?: InputMaybe<Scalars['ID']>;
lte?: InputMaybe<Scalars['ID']>;
neq?: InputMaybe<Scalars['ID']>;
notILike?: InputMaybe<Scalars['ID']>;
notIn?: InputMaybe<Array<Scalars['ID']>>;
notLike?: InputMaybe<Scalars['ID']>;
};
export type IntNullableFilter = { export type IntNullableFilter = {
equals?: InputMaybe<Scalars['Int']>; equals?: InputMaybe<Scalars['Int']>;
gt?: InputMaybe<Scalars['Int']>; gt?: InputMaybe<Scalars['Int']>;
@ -3117,6 +3140,7 @@ export type Field = {
isActive: Scalars['Boolean']; isActive: Scalars['Boolean'];
isCustom: Scalars['Boolean']; isCustom: Scalars['Boolean'];
isNullable: Scalars['Boolean']; isNullable: Scalars['Boolean'];
isSystem: Scalars['Boolean'];
label: Scalars['String']; label: Scalars['String'];
name: Scalars['String']; name: Scalars['String'];
/** @deprecated Use label name instead */ /** @deprecated Use label name instead */
@ -3134,6 +3158,15 @@ export type FieldEdge = {
node: Field; node: Field;
}; };
export type FieldFilter = {
and?: InputMaybe<Array<FieldFilter>>;
id?: InputMaybe<IdFilterComparison>;
isActive?: InputMaybe<BooleanFieldComparison>;
isCustom?: InputMaybe<BooleanFieldComparison>;
isSystem?: InputMaybe<BooleanFieldComparison>;
or?: InputMaybe<Array<FieldFilter>>;
};
export type Object = { export type Object = {
__typename?: 'object'; __typename?: 'object';
createdAt: Scalars['DateTime']; createdAt: Scalars['DateTime'];
@ -3154,6 +3187,7 @@ export type Object = {
export type ObjectFieldsArgs = { export type ObjectFieldsArgs = {
filter?: FieldFilter;
paging?: CursorPaging; paging?: CursorPaging;
}; };
@ -3233,94 +3267,6 @@ export type UserV2Edge = {
node: UserV2; node: UserV2;
}; };
export type ActivityWithTargetsFragment = { __typename?: 'Activity', id: string, createdAt: string, updatedAt: string, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, createdAt: string, updatedAt: string, companyId?: string | null, personId?: string | null }> | null };
export type ActivityQueryFragmentFragment = { __typename?: 'Activity', id: string, createdAt: string, title?: string | null, body?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null } | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, companyId?: string | null, personId?: string | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null, person?: { __typename?: 'Person', id: string, displayName: string, avatarUrl?: string | null } | null }> | null };
export type ActivityUpdatePartsFragment = { __typename?: 'Activity', id: string, body?: string | null, title?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string } | null };
export type AddActivityTargetsOnActivityMutationVariables = Exact<{
activityId: Scalars['String'];
activityTargetInputs: Array<ActivityTargetCreateManyActivityInput> | ActivityTargetCreateManyActivityInput;
}>;
export type AddActivityTargetsOnActivityMutation = { __typename?: 'Mutation', updateOneActivity: { __typename?: 'Activity', id: string, createdAt: string, updatedAt: string, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, createdAt: string, updatedAt: string, companyId?: string | null, personId?: string | null }> | null } };
export type CreateActivityMutationVariables = Exact<{
data: ActivityCreateInput;
}>;
export type CreateActivityMutation = { __typename?: 'Mutation', createOneActivity: { __typename?: 'Activity', id: string, createdAt: string, updatedAt: string, authorId: string, type: ActivityType, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, createdAt: string, updatedAt: string, activityId: string, companyId?: string | null, personId?: string | null }> | null, comments?: Array<{ __typename?: 'Comment', id: string, createdAt: string, updatedAt: string, body: string, author: { __typename?: 'User', id: string } }> | null } };
export type CreateCommentMutationVariables = Exact<{
commentId: Scalars['String'];
commentText: Scalars['String'];
authorId: Scalars['String'];
activityId: Scalars['String'];
createdAt: Scalars['DateTime'];
}>;
export type CreateCommentMutation = { __typename?: 'Mutation', createOneComment: { __typename?: 'Comment', id: string, createdAt: string, body: string, activityId?: string | null, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } } };
export type DeleteActivityMutationVariables = Exact<{
activityId: Scalars['String'];
}>;
export type DeleteActivityMutation = { __typename?: 'Mutation', deleteManyActivities: { __typename?: 'AffectedRows', count: number } };
export type RemoveActivityTargetsOnActivityMutationVariables = Exact<{
activityId: Scalars['String'];
activityTargetIds: Array<Scalars['String']> | Scalars['String'];
}>;
export type RemoveActivityTargetsOnActivityMutation = { __typename?: 'Mutation', updateOneActivity: { __typename?: 'Activity', id: string, createdAt: string, updatedAt: string, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, createdAt: string, updatedAt: string, companyId?: string | null, personId?: string | null }> | null } };
export type UpdateActivityMutationVariables = Exact<{
where: ActivityWhereUniqueInput;
data: ActivityUpdateInput;
}>;
export type UpdateActivityMutation = { __typename?: 'Mutation', updateOneActivity: { __typename?: 'Activity', id: string, body?: string | null, title?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string } | null } };
export type UploadAttachmentMutationVariables = Exact<{
file: Scalars['Upload'];
activityId: Scalars['String'];
companyId: Scalars['String'];
personId: Scalars['String'];
}>;
export type UploadAttachmentMutation = { __typename?: 'Mutation', uploadAttachment: string };
export type GetActivitiesQueryVariables = Exact<{
where: ActivityWhereInput;
orderBy?: InputMaybe<Array<ActivityOrderByWithRelationInput> | ActivityOrderByWithRelationInput>;
}>;
export type GetActivitiesQuery = { __typename?: 'Query', findManyActivities: Array<{ __typename?: 'Activity', id: string, createdAt: string, title?: string | null, body?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null } | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, companyId?: string | null, personId?: string | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null, person?: { __typename?: 'Person', id: string, displayName: string, avatarUrl?: string | null } | null }> | null }> };
export type GetActivitiesByTargetsQueryVariables = Exact<{
activityTargetIds: Array<Scalars['String']> | Scalars['String'];
orderBy?: InputMaybe<Array<ActivityOrderByWithRelationInput> | ActivityOrderByWithRelationInput>;
}>;
export type GetActivitiesByTargetsQuery = { __typename?: 'Query', findManyActivities: Array<{ __typename?: 'Activity', id: string, createdAt: string, title?: string | null, body?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null } | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, companyId?: string | null, personId?: string | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null, person?: { __typename?: 'Person', id: string, displayName: string, avatarUrl?: string | null } | null }> | null }> };
export type GetActivityQueryVariables = Exact<{
activityId: Scalars['String'];
}>;
export type GetActivityQuery = { __typename?: 'Query', findManyActivities: Array<{ __typename?: 'Activity', id: string, createdAt: string, title?: string | null, body?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null } | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, companyId?: string | null, personId?: string | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null, person?: { __typename?: 'Person', id: string, displayName: string, avatarUrl?: string | null } | null }> | null }> };
export type CreateEventMutationVariables = Exact<{ export type CreateEventMutationVariables = Exact<{
type: Scalars['String']; type: Scalars['String'];
data: Scalars['JSON']; data: Scalars['JSON'];
@ -3803,88 +3749,6 @@ export type GetWorkspaceMembersQueryVariables = Exact<{
export type GetWorkspaceMembersQuery = { __typename?: 'Query', workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: string }> }; export type GetWorkspaceMembersQuery = { __typename?: 'Query', workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: string }> };
export const ActivityWithTargetsFragmentDoc = gql`
fragment ActivityWithTargets on Activity {
id
createdAt
updatedAt
activityTargets {
id
createdAt
updatedAt
companyId
personId
}
}
`;
export const ActivityQueryFragmentFragmentDoc = gql`
fragment ActivityQueryFragment on Activity {
id
createdAt
title
body
type
completedAt
dueAt
assignee {
id
firstName
lastName
displayName
avatarUrl
}
author {
id
firstName
lastName
displayName
}
comments {
id
body
createdAt
updatedAt
author {
id
displayName
firstName
lastName
avatarUrl
}
}
activityTargets {
id
companyId
personId
company {
id
name
domainName
}
person {
id
displayName
avatarUrl
}
}
}
`;
export const ActivityUpdatePartsFragmentDoc = gql`
fragment ActivityUpdateParts on Activity {
id
body
title
type
completedAt
dueAt
assignee {
id
firstName
lastName
displayName
}
}
`;
export const AuthTokenFragmentFragmentDoc = gql` export const AuthTokenFragmentFragmentDoc = gql`
fragment AuthTokenFragment on AuthToken { fragment AuthTokenFragment on AuthToken {
token token
@ -3982,399 +3846,6 @@ export const UserFieldsFragmentFragmentDoc = gql`
lastName lastName
} }
`; `;
export const AddActivityTargetsOnActivityDocument = gql`
mutation AddActivityTargetsOnActivity($activityId: String!, $activityTargetInputs: [ActivityTargetCreateManyActivityInput!]!) {
updateOneActivity(
where: {id: $activityId}
data: {activityTargets: {createMany: {data: $activityTargetInputs}}}
) {
...ActivityWithTargets
}
}
${ActivityWithTargetsFragmentDoc}`;
export type AddActivityTargetsOnActivityMutationFn = Apollo.MutationFunction<AddActivityTargetsOnActivityMutation, AddActivityTargetsOnActivityMutationVariables>;
/**
* __useAddActivityTargetsOnActivityMutation__
*
* To run a mutation, you first call `useAddActivityTargetsOnActivityMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useAddActivityTargetsOnActivityMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [addActivityTargetsOnActivityMutation, { data, loading, error }] = useAddActivityTargetsOnActivityMutation({
* variables: {
* activityId: // value for 'activityId'
* activityTargetInputs: // value for 'activityTargetInputs'
* },
* });
*/
export function useAddActivityTargetsOnActivityMutation(baseOptions?: Apollo.MutationHookOptions<AddActivityTargetsOnActivityMutation, AddActivityTargetsOnActivityMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<AddActivityTargetsOnActivityMutation, AddActivityTargetsOnActivityMutationVariables>(AddActivityTargetsOnActivityDocument, options);
}
export type AddActivityTargetsOnActivityMutationHookResult = ReturnType<typeof useAddActivityTargetsOnActivityMutation>;
export type AddActivityTargetsOnActivityMutationResult = Apollo.MutationResult<AddActivityTargetsOnActivityMutation>;
export type AddActivityTargetsOnActivityMutationOptions = Apollo.BaseMutationOptions<AddActivityTargetsOnActivityMutation, AddActivityTargetsOnActivityMutationVariables>;
export const CreateActivityDocument = gql`
mutation CreateActivity($data: ActivityCreateInput!) {
createOneActivity(data: $data) {
id
createdAt
updatedAt
authorId
type
activityTargets {
id
createdAt
updatedAt
activityId
companyId
personId
}
comments {
id
createdAt
updatedAt
body
author {
id
}
}
}
}
`;
export type CreateActivityMutationFn = Apollo.MutationFunction<CreateActivityMutation, CreateActivityMutationVariables>;
/**
* __useCreateActivityMutation__
*
* To run a mutation, you first call `useCreateActivityMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateActivityMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [createActivityMutation, { data, loading, error }] = useCreateActivityMutation({
* variables: {
* data: // value for 'data'
* },
* });
*/
export function useCreateActivityMutation(baseOptions?: Apollo.MutationHookOptions<CreateActivityMutation, CreateActivityMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<CreateActivityMutation, CreateActivityMutationVariables>(CreateActivityDocument, options);
}
export type CreateActivityMutationHookResult = ReturnType<typeof useCreateActivityMutation>;
export type CreateActivityMutationResult = Apollo.MutationResult<CreateActivityMutation>;
export type CreateActivityMutationOptions = Apollo.BaseMutationOptions<CreateActivityMutation, CreateActivityMutationVariables>;
export const CreateCommentDocument = gql`
mutation CreateComment($commentId: String!, $commentText: String!, $authorId: String!, $activityId: String!, $createdAt: DateTime!) {
createOneComment(
data: {id: $commentId, createdAt: $createdAt, body: $commentText, author: {connect: {id: $authorId}}, activity: {connect: {id: $activityId}}}
) {
id
createdAt
body
author {
id
displayName
firstName
lastName
avatarUrl
}
activityId
}
}
`;
export type CreateCommentMutationFn = Apollo.MutationFunction<CreateCommentMutation, CreateCommentMutationVariables>;
/**
* __useCreateCommentMutation__
*
* To run a mutation, you first call `useCreateCommentMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useCreateCommentMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [createCommentMutation, { data, loading, error }] = useCreateCommentMutation({
* variables: {
* commentId: // value for 'commentId'
* commentText: // value for 'commentText'
* authorId: // value for 'authorId'
* activityId: // value for 'activityId'
* createdAt: // value for 'createdAt'
* },
* });
*/
export function useCreateCommentMutation(baseOptions?: Apollo.MutationHookOptions<CreateCommentMutation, CreateCommentMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<CreateCommentMutation, CreateCommentMutationVariables>(CreateCommentDocument, options);
}
export type CreateCommentMutationHookResult = ReturnType<typeof useCreateCommentMutation>;
export type CreateCommentMutationResult = Apollo.MutationResult<CreateCommentMutation>;
export type CreateCommentMutationOptions = Apollo.BaseMutationOptions<CreateCommentMutation, CreateCommentMutationVariables>;
export const DeleteActivityDocument = gql`
mutation DeleteActivity($activityId: String!) {
deleteManyActivities(where: {id: {equals: $activityId}}) {
count
}
}
`;
export type DeleteActivityMutationFn = Apollo.MutationFunction<DeleteActivityMutation, DeleteActivityMutationVariables>;
/**
* __useDeleteActivityMutation__
*
* To run a mutation, you first call `useDeleteActivityMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useDeleteActivityMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [deleteActivityMutation, { data, loading, error }] = useDeleteActivityMutation({
* variables: {
* activityId: // value for 'activityId'
* },
* });
*/
export function useDeleteActivityMutation(baseOptions?: Apollo.MutationHookOptions<DeleteActivityMutation, DeleteActivityMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<DeleteActivityMutation, DeleteActivityMutationVariables>(DeleteActivityDocument, options);
}
export type DeleteActivityMutationHookResult = ReturnType<typeof useDeleteActivityMutation>;
export type DeleteActivityMutationResult = Apollo.MutationResult<DeleteActivityMutation>;
export type DeleteActivityMutationOptions = Apollo.BaseMutationOptions<DeleteActivityMutation, DeleteActivityMutationVariables>;
export const RemoveActivityTargetsOnActivityDocument = gql`
mutation RemoveActivityTargetsOnActivity($activityId: String!, $activityTargetIds: [String!]!) {
updateOneActivity(
where: {id: $activityId}
data: {activityTargets: {deleteMany: {id: {in: $activityTargetIds}}}}
) {
...ActivityWithTargets
}
}
${ActivityWithTargetsFragmentDoc}`;
export type RemoveActivityTargetsOnActivityMutationFn = Apollo.MutationFunction<RemoveActivityTargetsOnActivityMutation, RemoveActivityTargetsOnActivityMutationVariables>;
/**
* __useRemoveActivityTargetsOnActivityMutation__
*
* To run a mutation, you first call `useRemoveActivityTargetsOnActivityMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useRemoveActivityTargetsOnActivityMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [removeActivityTargetsOnActivityMutation, { data, loading, error }] = useRemoveActivityTargetsOnActivityMutation({
* variables: {
* activityId: // value for 'activityId'
* activityTargetIds: // value for 'activityTargetIds'
* },
* });
*/
export function useRemoveActivityTargetsOnActivityMutation(baseOptions?: Apollo.MutationHookOptions<RemoveActivityTargetsOnActivityMutation, RemoveActivityTargetsOnActivityMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<RemoveActivityTargetsOnActivityMutation, RemoveActivityTargetsOnActivityMutationVariables>(RemoveActivityTargetsOnActivityDocument, options);
}
export type RemoveActivityTargetsOnActivityMutationHookResult = ReturnType<typeof useRemoveActivityTargetsOnActivityMutation>;
export type RemoveActivityTargetsOnActivityMutationResult = Apollo.MutationResult<RemoveActivityTargetsOnActivityMutation>;
export type RemoveActivityTargetsOnActivityMutationOptions = Apollo.BaseMutationOptions<RemoveActivityTargetsOnActivityMutation, RemoveActivityTargetsOnActivityMutationVariables>;
export const UpdateActivityDocument = gql`
mutation UpdateActivity($where: ActivityWhereUniqueInput!, $data: ActivityUpdateInput!) {
updateOneActivity(where: $where, data: $data) {
...ActivityUpdateParts
}
}
${ActivityUpdatePartsFragmentDoc}`;
export type UpdateActivityMutationFn = Apollo.MutationFunction<UpdateActivityMutation, UpdateActivityMutationVariables>;
/**
* __useUpdateActivityMutation__
*
* To run a mutation, you first call `useUpdateActivityMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUpdateActivityMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [updateActivityMutation, { data, loading, error }] = useUpdateActivityMutation({
* variables: {
* where: // value for 'where'
* data: // value for 'data'
* },
* });
*/
export function useUpdateActivityMutation(baseOptions?: Apollo.MutationHookOptions<UpdateActivityMutation, UpdateActivityMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<UpdateActivityMutation, UpdateActivityMutationVariables>(UpdateActivityDocument, options);
}
export type UpdateActivityMutationHookResult = ReturnType<typeof useUpdateActivityMutation>;
export type UpdateActivityMutationResult = Apollo.MutationResult<UpdateActivityMutation>;
export type UpdateActivityMutationOptions = Apollo.BaseMutationOptions<UpdateActivityMutation, UpdateActivityMutationVariables>;
export const UploadAttachmentDocument = gql`
mutation UploadAttachment($file: Upload!, $activityId: String!, $companyId: String!, $personId: String!) {
uploadAttachment(
file: $file
activityId: $activityId
companyId: $companyId
personId: $personId
)
}
`;
export type UploadAttachmentMutationFn = Apollo.MutationFunction<UploadAttachmentMutation, UploadAttachmentMutationVariables>;
/**
* __useUploadAttachmentMutation__
*
* To run a mutation, you first call `useUploadAttachmentMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useUploadAttachmentMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [uploadAttachmentMutation, { data, loading, error }] = useUploadAttachmentMutation({
* variables: {
* file: // value for 'file'
* activityId: // value for 'activityId'
* companyId: // value for 'companyId'
* personId: // value for 'personId'
* },
* });
*/
export function useUploadAttachmentMutation(baseOptions?: Apollo.MutationHookOptions<UploadAttachmentMutation, UploadAttachmentMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<UploadAttachmentMutation, UploadAttachmentMutationVariables>(UploadAttachmentDocument, options);
}
export type UploadAttachmentMutationHookResult = ReturnType<typeof useUploadAttachmentMutation>;
export type UploadAttachmentMutationResult = Apollo.MutationResult<UploadAttachmentMutation>;
export type UploadAttachmentMutationOptions = Apollo.BaseMutationOptions<UploadAttachmentMutation, UploadAttachmentMutationVariables>;
export const GetActivitiesDocument = gql`
query GetActivities($where: ActivityWhereInput!, $orderBy: [ActivityOrderByWithRelationInput!]) {
findManyActivities(orderBy: $orderBy, where: $where) {
...ActivityQueryFragment
}
}
${ActivityQueryFragmentFragmentDoc}`;
/**
* __useGetActivitiesQuery__
*
* To run a query within a React component, call `useGetActivitiesQuery` and pass it any options that fit your needs.
* When your component renders, `useGetActivitiesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetActivitiesQuery({
* variables: {
* where: // value for 'where'
* orderBy: // value for 'orderBy'
* },
* });
*/
export function useGetActivitiesQuery(baseOptions: Apollo.QueryHookOptions<GetActivitiesQuery, GetActivitiesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetActivitiesQuery, GetActivitiesQueryVariables>(GetActivitiesDocument, options);
}
export function useGetActivitiesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetActivitiesQuery, GetActivitiesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetActivitiesQuery, GetActivitiesQueryVariables>(GetActivitiesDocument, options);
}
export type GetActivitiesQueryHookResult = ReturnType<typeof useGetActivitiesQuery>;
export type GetActivitiesLazyQueryHookResult = ReturnType<typeof useGetActivitiesLazyQuery>;
export type GetActivitiesQueryResult = Apollo.QueryResult<GetActivitiesQuery, GetActivitiesQueryVariables>;
export const GetActivitiesByTargetsDocument = gql`
query GetActivitiesByTargets($activityTargetIds: [String!]!, $orderBy: [ActivityOrderByWithRelationInput!]) {
findManyActivities(
orderBy: $orderBy
where: {activityTargets: {some: {OR: [{personId: {in: $activityTargetIds}}, {companyId: {in: $activityTargetIds}}]}}}
) {
...ActivityQueryFragment
}
}
${ActivityQueryFragmentFragmentDoc}`;
/**
* __useGetActivitiesByTargetsQuery__
*
* To run a query within a React component, call `useGetActivitiesByTargetsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetActivitiesByTargetsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetActivitiesByTargetsQuery({
* variables: {
* activityTargetIds: // value for 'activityTargetIds'
* orderBy: // value for 'orderBy'
* },
* });
*/
export function useGetActivitiesByTargetsQuery(baseOptions: Apollo.QueryHookOptions<GetActivitiesByTargetsQuery, GetActivitiesByTargetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetActivitiesByTargetsQuery, GetActivitiesByTargetsQueryVariables>(GetActivitiesByTargetsDocument, options);
}
export function useGetActivitiesByTargetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetActivitiesByTargetsQuery, GetActivitiesByTargetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetActivitiesByTargetsQuery, GetActivitiesByTargetsQueryVariables>(GetActivitiesByTargetsDocument, options);
}
export type GetActivitiesByTargetsQueryHookResult = ReturnType<typeof useGetActivitiesByTargetsQuery>;
export type GetActivitiesByTargetsLazyQueryHookResult = ReturnType<typeof useGetActivitiesByTargetsLazyQuery>;
export type GetActivitiesByTargetsQueryResult = Apollo.QueryResult<GetActivitiesByTargetsQuery, GetActivitiesByTargetsQueryVariables>;
export const GetActivityDocument = gql`
query GetActivity($activityId: String!) {
findManyActivities(where: {id: {equals: $activityId}}) {
...ActivityQueryFragment
}
}
${ActivityQueryFragmentFragmentDoc}`;
/**
* __useGetActivityQuery__
*
* To run a query within a React component, call `useGetActivityQuery` and pass it any options that fit your needs.
* When your component renders, `useGetActivityQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetActivityQuery({
* variables: {
* activityId: // value for 'activityId'
* },
* });
*/
export function useGetActivityQuery(baseOptions: Apollo.QueryHookOptions<GetActivityQuery, GetActivityQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetActivityQuery, GetActivityQueryVariables>(GetActivityDocument, options);
}
export function useGetActivityLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetActivityQuery, GetActivityQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetActivityQuery, GetActivityQueryVariables>(GetActivityDocument, options);
}
export type GetActivityQueryHookResult = ReturnType<typeof useGetActivityQuery>;
export type GetActivityLazyQueryHookResult = ReturnType<typeof useGetActivityLazyQuery>;
export type GetActivityQueryResult = Apollo.QueryResult<GetActivityQuery, GetActivityQueryVariables>;
export const CreateEventDocument = gql` export const CreateEventDocument = gql`
mutation CreateEvent($type: String!, $data: JSON!) { mutation CreateEvent($type: String!, $data: JSON!) {
createEvent(type: $type, data: $data) { createEvent(type: $type, data: $data) {

View File

@ -1,11 +1,11 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { CommentForDrawer } from '../types/CommentForDrawer'; import { Comment as CommentType } from '@/activities/types/Comment';
import { CommentHeader } from './CommentHeader'; import { CommentHeader } from './CommentHeader';
type CommentProps = { type CommentProps = {
comment: CommentForDrawer; comment: Omit<CommentType, 'activityId'>;
actionBar?: React.ReactNode; actionBar?: React.ReactNode;
}; };

View File

@ -1,16 +1,15 @@
import { Tooltip } from 'react-tooltip'; import { Tooltip } from 'react-tooltip';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { Comment } from '@/activities/types/Comment';
import { Avatar } from '@/users/components/Avatar'; import { Avatar } from '@/users/components/Avatar';
import { import {
beautifyExactDateTime, beautifyExactDateTime,
beautifyPastDateRelativeToNow, beautifyPastDateRelativeToNow,
} from '~/utils/date-utils'; } from '~/utils/date-utils';
import { CommentForDrawer } from '../types/CommentForDrawer';
type CommentHeaderProps = { type CommentHeaderProps = {
comment: Pick<CommentForDrawer, 'id' | 'author' | 'createdAt'>; comment: Pick<Comment, 'id' | 'author' | 'createdAt'>;
actionBar?: React.ReactNode; actionBar?: React.ReactNode;
}; };
@ -68,7 +67,7 @@ export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => {
const showDate = beautifiedCreatedAt !== ''; const showDate = beautifiedCreatedAt !== '';
const author = comment.author; const author = comment.author;
const authorName = author.displayName; const authorName = author.firstName + ' ' + author.lastName;
const avatarUrl = author.avatarUrl; const avatarUrl = author.avatarUrl;
const commentId = comment.id; const commentId = comment.id;
@ -79,7 +78,7 @@ export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => {
avatarUrl={avatarUrl} avatarUrl={avatarUrl}
size="md" size="md"
colorId={author.id} colorId={author.id}
placeholder={author.displayName} placeholder={authorName}
/> />
<StyledName>{authorName}</StyledName> <StyledName>{authorName}</StyledName>
{showDate && ( {showDate && (

View File

@ -1,39 +1,34 @@
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { CommentForDrawer } from '@/activities/types/CommentForDrawer'; import { Comment } from '@/activities/types/Comment';
import { mockedUsersData } from '~/testing/mock-data/users';
const mockUser = mockedUsersData[0];
export const mockComment: Pick< export const mockComment: Pick<
CommentForDrawer, Comment,
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt' 'id' | 'author' | 'createdAt' | 'body' | 'updatedAt'
> = { > = {
id: 'fake_comment_1_uuid', id: 'fake_comment_1_uuid',
body: 'Hello, this is a comment.', body: 'Hello, this is a comment.',
author: { author: {
id: 'fake_comment_1_author_uuid', id: 'fake_comment_1_author_uuid',
displayName: mockUser.displayName ?? '', firstName: 'Jony' ?? '',
firstName: mockUser.firstName ?? '', lastName: 'Ive' ?? '',
lastName: mockUser.lastName ?? '', avatarUrl: null,
avatarUrl: mockUser.avatarUrl,
}, },
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() ?? '',
}; };
export const mockCommentWithLongValues: Pick< export const mockCommentWithLongValues: Pick<
CommentForDrawer, Comment,
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt' 'id' | 'author' | 'createdAt' | 'body' | 'updatedAt'
> = { > = {
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.',
author: { author: {
id: 'fake_comment_2_author_uuid', id: 'fake_comment_1_author_uuid',
displayName: mockUser.displayName + ' with a very long suffix' ?? '', firstName: 'Jony' ?? '',
firstName: mockUser.firstName ?? '', lastName: 'Ive' ?? '',
lastName: mockUser.lastName ?? '', avatarUrl: null,
avatarUrl: mockUser.avatarUrl,
}, },
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() ?? '',

View File

@ -1,26 +1,23 @@
import { useApolloClient } from '@apollo/client'; import { Activity } from '@/activities/types/Activity';
import { getOperationName } from '@apollo/client/utilities'; import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect'; import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect'; import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { import {
Activity,
useGetWorkspaceMembersLazyQuery, useGetWorkspaceMembersLazyQuery,
User,
useSearchUserQuery, useSearchUserQuery,
useUpdateActivityMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment';
import { GET_ACTIVITIES } from '../graphql/queries/getActivities';
export type ActivityAssigneePickerProps = { export type ActivityAssigneePickerProps = {
activity: Pick<Activity, 'id'> & { activity: Pick<Activity, 'id'> & {
accountOwner?: Pick<User, 'id' | 'displayName'> | null; accountOwner?: Pick<
WorkspaceMember,
'id' | 'firstName' | 'lastName'
> | null;
}; };
onSubmit?: () => void; onSubmit?: () => void;
onCancel?: () => void; onCancel?: () => void;
@ -38,7 +35,9 @@ export const ActivityAssigneePicker = ({
const [relationPickerSearchFilter] = useRecoilScopedState( const [relationPickerSearchFilter] = useRecoilScopedState(
relationPickerSearchFilterScopedState, relationPickerSearchFilterScopedState,
); );
const [updateActivity] = useUpdateActivityMutation(); const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'ActivityV2',
});
const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery(); const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery();
const users = useFilteredSearchEntityQuery({ const users = useFilteredSearchEntityQuery({
@ -63,12 +62,6 @@ export const ActivityAssigneePicker = ({
selectedIds: activity?.accountOwner?.id ? [activity?.accountOwner?.id] : [], selectedIds: activity?.accountOwner?.id ? [activity?.accountOwner?.id] : [],
}); });
const client = useApolloClient();
const cachedActivity = client.readFragment({
id: `Activity:${activity.id}`,
fragment: ACTIVITY_UPDATE_FRAGMENT,
});
const handleEntitySelected = async ( const handleEntitySelected = async (
selectedUser: UserForSelect | null | undefined, selectedUser: UserForSelect | null | undefined,
) => { ) => {
@ -83,28 +76,14 @@ export const ActivityAssigneePicker = ({
}) })
).data?.workspaceMembers?.[0]; ).data?.workspaceMembers?.[0];
updateActivity({ updateOneObject?.({
variables: { idToUpdate: activity.id,
where: { id: activity.id }, input: {
data: { assignee: { connect: { id: selectedUser.id } },
assignee: { connect: { id: selectedUser.id } }, workspaceMemberAssignee: {
workspaceMemberAssignee: { connect: { id: workspaceMemberAssignee?.id },
connect: { id: workspaceMemberAssignee?.id },
},
}, },
}, },
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
...cachedActivity,
assignee: {
__typename: 'User',
...selectedUser,
displayName: selectedUser.name,
},
},
},
refetchQueries: [getOperationName(GET_ACTIVITIES) ?? ''],
}); });
} }

View File

@ -1,14 +1,12 @@
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { useApolloClient } from '@apollo/client';
import { BlockNoteEditor } from '@blocknote/core'; import { BlockNoteEditor } from '@blocknote/core';
import { useBlockNote } from '@blocknote/react'; import { useBlockNote } from '@blocknote/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
import { Activity } from '@/activities/types/Activity';
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { BlockEditor } from '@/ui/input/editor/components/BlockEditor'; import { BlockEditor } from '@/ui/input/editor/components/BlockEditor';
import { Activity, useUpdateActivityMutation } from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment';
const StyledBlockNoteStyledContainer = styled.div` const StyledBlockNoteStyledContainer = styled.div`
width: 100%; width: 100%;
@ -23,15 +21,10 @@ export const ActivityBodyEditor = ({
activity, activity,
onChange, onChange,
}: ActivityBodyEditorProps) => { }: ActivityBodyEditorProps) => {
const [updateActivityMutation] = useUpdateActivityMutation();
const client = useApolloClient();
const cachedActivity = client.readFragment({
id: `Activity:${activity.id}`,
fragment: ACTIVITY_UPDATE_FRAGMENT,
});
const [body, setBody] = useState<string | null>(null); const [body, setBody] = useState<string | null>(null);
const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'ActivityV2',
});
useEffect(() => { useEffect(() => {
if (body) { if (body) {
@ -42,27 +35,16 @@ export const ActivityBodyEditor = ({
const debounceOnChange = useMemo(() => { const debounceOnChange = useMemo(() => {
const onInternalChange = (activityBody: string) => { const onInternalChange = (activityBody: string) => {
setBody(activityBody); setBody(activityBody);
updateActivityMutation({ updateOneObject?.({
variables: { idToUpdate: activity.id,
where: { input: {
id: activity.id, body: activityBody,
},
data: {
body: activityBody,
},
},
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
...cachedActivity,
body: activityBody,
},
}, },
}); });
}; };
return debounce(onInternalChange, 200); return debounce(onInternalChange, 200);
}, [updateActivityMutation, activity.id, cachedActivity]); }, [updateOneObject, activity.id]);
const editor: BlockNoteEditor | null = useBlockNote({ const editor: BlockNoteEditor | null = useBlockNote({
initialContent: activity.body ? JSON.parse(activity.body) : undefined, initialContent: activity.body ? JSON.parse(activity.body) : undefined,

View File

@ -1,24 +1,22 @@
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards'; import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { Comment } from '@/activities/comment/Comment';
import { Activity } from '@/activities/types/Activity';
import { Comment as CommentType } from '@/activities/types/Comment';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
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';
import { Activity, useCreateCommentMutation } from '~/generated/graphql';
import { Comment } from '../comment/Comment';
import { GET_ACTIVITY } from '../graphql/queries/getActivity';
import { CommentForDrawer } from '../types/CommentForDrawer';
type ActivityCommentsProps = { type ActivityCommentsProps = {
activity: Pick<Activity, 'id'> & { activity: Pick<Activity, 'id'> & {
comments: Array<CommentForDrawer>; comments: Array<CommentType>;
}; };
scrollableContainerRef: React.RefObject<HTMLDivElement>; scrollableContainerRef: React.RefObject<HTMLDivElement>;
}; };
@ -63,8 +61,10 @@ export const ActivityComments = ({
activity, activity,
scrollableContainerRef, scrollableContainerRef,
}: ActivityCommentsProps) => { }: ActivityCommentsProps) => {
const [createCommentMutation] = useCreateCommentMutation();
const currentUser = useRecoilValue(currentUserState); const currentUser = useRecoilValue(currentUserState);
const { createOneObject } = useCreateOneObjectRecord({
objectNamePlural: 'commentsV2',
});
if (!currentUser) { if (!currentUser) {
return <></>; return <></>;
@ -75,21 +75,12 @@ export const ActivityComments = ({
return; return;
} }
createCommentMutation({ createOneObject?.({
variables: { commentId: v4(),
commentId: v4(), authorId: currentUser?.id ?? '',
authorId: currentUser?.id ?? '', activityId: activity?.id ?? '',
activityId: activity?.id ?? '', commentText: commentText,
commentText: commentText, createdAt: new Date().toISOString(),
createdAt: new Date().toISOString(),
},
refetchQueries: [getOperationName(GET_ACTIVITY) ?? ''],
onCompleted: () => {
setTimeout(() => {
handleFocus();
}, 100);
},
awaitRefetchQueries: true,
}); });
}; };

View File

@ -1,29 +1,22 @@
import React, { useCallback, useRef, useState } from 'react'; import React, { useCallback, useRef, useState } from 'react';
import { useApolloClient } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { ActivityBodyEditor } from '@/activities/components/ActivityBodyEditor'; import { ActivityBodyEditor } from '@/activities/components/ActivityBodyEditor';
import { ActivityComments } from '@/activities/components/ActivityComments'; import { ActivityComments } from '@/activities/components/ActivityComments';
import { ActivityTypeDropdown } from '@/activities/components/ActivityTypeDropdown'; import { ActivityTypeDropdown } from '@/activities/components/ActivityTypeDropdown';
import { GET_ACTIVITIES } from '@/activities/graphql/queries/getActivities'; import { Activity } from '@/activities/types/Activity';
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { Comment } from '@/activities/types/Comment';
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { PropertyBox } from '@/ui/object/record-inline-cell/property-box/components/PropertyBox'; import { PropertyBox } from '@/ui/object/record-inline-cell/property-box/components/PropertyBox';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
Activity,
ActivityTarget,
ActivityType,
User,
useUpdateActivityMutation,
} from '~/generated/graphql';
import { debounce } from '~/utils/debounce'; import { debounce } from '~/utils/debounce';
import { ActivityAssigneeEditableField } from '../editable-fields/components/ActivityAssigneeEditableField'; import { ActivityAssigneeEditableField } from '../editable-fields/components/ActivityAssigneeEditableField';
import { ActivityEditorDateField } from '../editable-fields/components/ActivityEditorDateField'; import { ActivityEditorDateField } from '../editable-fields/components/ActivityEditorDateField';
import { ActivityRelationEditableField } from '../editable-fields/components/ActivityRelationEditableField'; import { ActivityRelationEditableField } from '../editable-fields/components/ActivityRelationEditableField';
import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment';
import { CommentForDrawer } from '../types/CommentForDrawer';
import { ActivityTitle } from './ActivityTitle'; import { ActivityTitle } from './ActivityTitle';
@ -65,14 +58,16 @@ type ActivityEditorProps = {
Activity, Activity,
'id' | 'title' | 'body' | 'type' | 'completedAt' | 'dueAt' 'id' | 'title' | 'body' | 'type' | 'completedAt' | 'dueAt'
> & { > & {
comments?: Array<CommentForDrawer> | null; comments?: Array<Comment> | null;
} & { } & {
assignee?: Pick< assignee?: Pick<
User, WorkspaceMember,
'id' | 'firstName' | 'lastName' | 'displayName' 'id' | 'firstName' | 'lastName' | 'avatarUrl'
> | null; > | null;
} & { } & {
activityTargets?: Array<Pick<ActivityTarget, 'id'>> | null; activityTargets?: Array<
Pick<ActivityTarget, 'id' | 'companyId' | 'personId'>
> | null;
}; };
showComment?: boolean; showComment?: boolean;
autoFillTitle?: boolean; autoFillTitle?: boolean;
@ -91,64 +86,32 @@ export const ActivityEditor = ({
activity.completedAt ?? '', activity.completedAt ?? '',
); );
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const { updateOneObject } = useUpdateOneObjectRecord({
const [updateActivityMutation] = useUpdateActivityMutation(); objectNamePlural: 'activitiesV2',
const client = useApolloClient();
const cachedActivity = client.readFragment({
id: `Activity:${activity.id}`,
fragment: ACTIVITY_UPDATE_FRAGMENT,
}); });
const updateTitle = useCallback( const updateTitle = useCallback(
(newTitle: string) => { (newTitle: string) => {
updateActivityMutation({ updateOneObject?.({
variables: { idToUpdate: activity.id,
where: { input: {
id: activity.id, title: newTitle ?? '',
},
data: {
title: newTitle ?? '',
},
}, },
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
__typename: 'Activity',
...cachedActivity,
title: newTitle,
},
},
refetchQueries: [getOperationName(GET_ACTIVITIES) ?? ''],
}); });
}, },
[activity.id, cachedActivity, updateActivityMutation], [activity.id, updateOneObject],
); );
const handleActivityCompletionChange = useCallback( const handleActivityCompletionChange = useCallback(
(value: boolean) => { (value: boolean) => {
updateActivityMutation({ updateOneObject?.({
variables: { idToUpdate: activity.id,
where: { input: {
id: activity.id, completedAt: value ? new Date().toISOString() : null,
},
data: {
completedAt: value ? new Date().toISOString() : null,
},
}, },
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
__typename: 'Activity',
...cachedActivity,
completedAt: value ? new Date().toISOString() : null,
},
},
refetchQueries: [getOperationName(GET_ACTIVITIES) ?? ''],
}); });
setCompletedAt(value ? new Date().toISOString() : null); setCompletedAt(value ? new Date().toISOString() : null);
}, },
[activity.id, cachedActivity, updateActivityMutation], [activity.id, updateOneObject],
); );
const debouncedUpdateTitle = debounce(updateTitle, 200); const debouncedUpdateTitle = debounce(updateTitle, 200);
@ -182,7 +145,7 @@ export const ActivityEditor = ({
onCompletionChange={handleActivityCompletionChange} onCompletionChange={handleActivityCompletionChange}
/> />
<PropertyBox> <PropertyBox>
{activity.type === ActivityType.Task && ( {activity.type === 'Task' && (
<> <>
<RecoilScope> <RecoilScope>
<ActivityEditorDateField activityId={activity.id} /> <ActivityEditorDateField activityId={activity.id} />

View File

@ -1,8 +1,9 @@
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 { PersonChip } from '@/people/components/PersonChip'; import { PersonChip } from '@/people/components/PersonChip';
import { ActivityTarget, Company, Person } from '~/generated/graphql'; import { Company, Person } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils'; import { getLogoUrlFromDomainName } from '~/utils';
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -16,7 +17,10 @@ export const ActivityTargetChips = ({
}: { }: {
targets?: Array< targets?: Array<
Pick<ActivityTarget, 'id'> & { Pick<ActivityTarget, 'id'> & {
person?: Pick<Person, 'id' | 'displayName' | 'avatarUrl'> | null; person?: Pick<
Person,
'id' | 'firstName' | 'lastName' | 'avatarUrl'
> | null;
company?: Pick<Company, 'id' | 'domainName' | 'name'> | null; company?: Pick<Company, 'id' | 'domainName' | 'name'> | null;
} }
> | null; > | null;
@ -43,7 +47,7 @@ export const ActivityTargetChips = ({
<PersonChip <PersonChip
key={person.id} key={person.id}
id={person.id} id={person.id}
name={person.displayName} name={person.firstName + ' ' + person.lastName}
pictureUrl={person.avatarUrl ?? undefined} pictureUrl={person.avatarUrl ?? undefined}
/> />
); );

View File

@ -1,11 +1,11 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { ActivityType } from '@/activities/types/Activity';
import { import {
Checkbox, Checkbox,
CheckboxShape, CheckboxShape,
CheckboxSize, CheckboxSize,
} from '@/ui/input/components/Checkbox'; } from '@/ui/input/components/Checkbox';
import { ActivityType } from '~/generated/graphql';
const StyledEditableTitleInput = styled.input<{ const StyledEditableTitleInput = styled.input<{
completed: boolean; completed: boolean;
@ -60,7 +60,7 @@ export const ActivityTitle = ({
onCompletionChange, onCompletionChange,
}: ActivityTitleProps) => ( }: ActivityTitleProps) => (
<StyledContainer> <StyledContainer>
{type === ActivityType.Task && ( {type === 'Task' && (
<StyledCheckboxContainer onClick={() => onCompletionChange(!completed)}> <StyledCheckboxContainer onClick={() => onCompletionChange(!completed)}>
<Checkbox <Checkbox
size={CheckboxSize.Large} size={CheckboxSize.Large}

View File

@ -1,5 +1,6 @@
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import { Activity } from '@/activities/types/Activity';
import { import {
Chip, Chip,
ChipAccent, ChipAccent,
@ -7,7 +8,6 @@ import {
ChipVariant, ChipVariant,
} from '@/ui/display/chip/components/Chip'; } from '@/ui/display/chip/components/Chip';
import { IconCheckbox, IconNotes } from '@/ui/display/icon'; import { IconCheckbox, IconNotes } from '@/ui/display/icon';
import { Activity, ActivityType } from '~/generated/graphql';
type ActivityTypeDropdownProps = { type ActivityTypeDropdownProps = {
activity: Pick<Activity, 'type'>; activity: Pick<Activity, 'type'>;
@ -21,7 +21,7 @@ export const ActivityTypeDropdown = ({
<Chip <Chip
label={activity.type} label={activity.type}
leftComponent={ leftComponent={
activity.type === ActivityType.Note ? ( activity.type === 'Note' ? (
<IconNotes size={theme.icon.size.md} /> <IconNotes size={theme.icon.size.md} />
) : ( ) : (
<IconCheckbox size={theme.icon.size.md} /> <IconCheckbox size={theme.icon.size.md} />

View File

@ -1,5 +1,6 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { IconUserCircle } from '@/ui/display/icon'; import { IconUserCircle } from '@/ui/display/icon';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect'; import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { FieldContext } from '@/ui/object/field/contexts/FieldContext'; import { FieldContext } from '@/ui/object/field/contexts/FieldContext';
@ -7,17 +8,44 @@ import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition';
import { FieldRelationMetadata } from '@/ui/object/field/types/FieldMetadata'; import { FieldRelationMetadata } from '@/ui/object/field/types/FieldMetadata';
import { RecordInlineCell } from '@/ui/object/record-inline-cell/components/RecordInlineCell'; import { RecordInlineCell } from '@/ui/object/record-inline-cell/components/RecordInlineCell';
import { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope'; import { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope';
import { Company, User, useUpdateActivityMutation } from '~/generated/graphql'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { Company, User } from '~/generated/graphql';
type ActivityAssigneeEditableFieldProps = { type ActivityAssigneeEditableFieldProps = {
activity: Pick<Company, 'id' | 'accountOwnerId'> & { activity: Pick<Company, 'id' | 'accountOwnerId'> & {
assignee?: Pick<User, 'id' | 'displayName' | 'avatarUrl'> | null; assignee?: Pick<
WorkspaceMember,
'id' | 'firstName' | 'lastName' | 'avatarUrl'
> | null;
}; };
}; };
export const ActivityAssigneeEditableField = ({ export const ActivityAssigneeEditableField = ({
activity, activity,
}: ActivityAssigneeEditableFieldProps) => { }: ActivityAssigneeEditableFieldProps) => {
const useUpdateOneObjectMutation: () => [(params: any) => any, any] = () => {
const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'activityV2',
});
const updateEntity = ({
variables,
}: {
variables: {
where: { id: string };
data: {
[fieldName: string]: any;
};
};
}) => {
updateOneObject?.({
idToUpdate: variables.where.id,
input: variables.data,
});
};
return [updateEntity, { loading: false }];
};
const value = useMemo( const value = useMemo(
() => ({ () => ({
entityId: activity.id, entityId: activity.id,
@ -39,7 +67,7 @@ export const ActivityAssigneeEditableField = ({
}; };
}, },
} satisfies FieldDefinition<FieldRelationMetadata>, } satisfies FieldDefinition<FieldRelationMetadata>,
useUpdateEntityMutation: useUpdateActivityMutation, useUpdateEntityMutation: useUpdateOneObjectMutation,
hotkeyScope: InlineCellHotkeyScope.InlineCell, hotkeyScope: InlineCellHotkeyScope.InlineCell,
}), }),
[activity.id], [activity.id],

View File

@ -1,3 +1,4 @@
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { IconCalendar } from '@/ui/display/icon/index'; import { IconCalendar } from '@/ui/display/icon/index';
import { FieldContext } from '@/ui/object/field/contexts/FieldContext'; import { FieldContext } from '@/ui/object/field/contexts/FieldContext';
import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition'; import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition';
@ -5,7 +6,6 @@ import { FieldDateMetadata } from '@/ui/object/field/types/FieldMetadata';
import { RecordInlineCell } from '@/ui/object/record-inline-cell/components/RecordInlineCell'; import { RecordInlineCell } from '@/ui/object/record-inline-cell/components/RecordInlineCell';
import { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope'; import { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useUpdateActivityMutation } from '~/generated/graphql';
type ActivityEditorDateFieldProps = { type ActivityEditorDateFieldProps = {
activityId: string; activityId: string;
@ -14,6 +14,30 @@ type ActivityEditorDateFieldProps = {
export const ActivityEditorDateField = ({ export const ActivityEditorDateField = ({
activityId, activityId,
}: ActivityEditorDateFieldProps) => { }: ActivityEditorDateFieldProps) => {
const useUpdateOneObjectMutation: () => [(params: any) => any, any] = () => {
const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'activityV2',
});
const updateEntity = ({
variables,
}: {
variables: {
where: { id: string };
data: {
[fieldName: string]: any;
};
};
}) => {
updateOneObject?.({
idToUpdate: variables.where.id,
input: variables.data,
});
};
return [updateEntity, { loading: false }];
};
return ( return (
<RecoilScope> <RecoilScope>
<FieldContext.Provider <FieldContext.Provider
@ -29,7 +53,7 @@ export const ActivityEditorDateField = ({
fieldName: 'dueAt', fieldName: 'dueAt',
}, },
} satisfies FieldDefinition<FieldDateMetadata>, } satisfies FieldDefinition<FieldDateMetadata>,
useUpdateEntityMutation: useUpdateActivityMutation, useUpdateEntityMutation: useUpdateOneObjectMutation,
hotkeyScope: InlineCellHotkeyScope.InlineCell, hotkeyScope: InlineCellHotkeyScope.InlineCell,
}} }}
> >

View File

@ -1,10 +1,12 @@
import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips'; import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips';
import { Activity } from '@/activities/types/Activity';
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { IconArrowUpRight, IconPencil } from '@/ui/display/icon'; import { IconArrowUpRight, IconPencil } from '@/ui/display/icon';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { RecordInlineCellContainer } from '@/ui/object/record-inline-cell/components/RecordInlineCellContainer'; import { RecordInlineCellContainer } from '@/ui/object/record-inline-cell/components/RecordInlineCellContainer';
import { FieldRecoilScopeContext } from '@/ui/object/record-inline-cell/states/recoil-scope-contexts/FieldRecoilScopeContext'; import { FieldRecoilScopeContext } from '@/ui/object/record-inline-cell/states/recoil-scope-contexts/FieldRecoilScopeContext';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { Activity, ActivityTarget, Company, Person } from '~/generated/graphql'; import { Company, Person } from '~/generated/graphql';
import { ActivityRelationEditableFieldEditMode } from './ActivityRelationEditableFieldEditMode'; import { ActivityRelationEditableFieldEditMode } from './ActivityRelationEditableFieldEditMode';
@ -12,8 +14,8 @@ type ActivityRelationEditableFieldProps = {
activity?: Pick<Activity, 'id'> & { activity?: Pick<Activity, 'id'> & {
activityTargets?: Array< activityTargets?: Array<
Pick<ActivityTarget, 'id' | 'personId' | 'companyId'> & { Pick<ActivityTarget, 'id' | 'personId' | 'companyId'> & {
person?: Pick<Person, 'id' | 'displayName'>; person?: Pick<Person, 'id' | 'firstName' | 'lastName'> | null;
company?: Pick<Company, 'id' | 'domainName' | 'name'>; company?: Pick<Company, 'id' | 'domainName' | 'name'> | null;
} }
> | null; > | null;
}; };

View File

@ -2,12 +2,13 @@ import { useCallback, useMemo, useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useHandleCheckableActivityTargetChange } from '@/activities/hooks/useHandleCheckableActivityTargetChange'; import { useHandleCheckableActivityTargetChange } from '@/activities/hooks/useHandleCheckableActivityTargetChange';
import { Activity } from '@/activities/types/Activity';
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/activities/utils/flatMapAndSortEntityForSelectArrayByName'; import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/activities/utils/flatMapAndSortEntityForSelectArrayByName';
import { useFilteredSearchCompanyQuery } from '@/companies/hooks/useFilteredSearchCompanyQuery'; import { useFilteredSearchCompanyQuery } from '@/companies/hooks/useFilteredSearchCompanyQuery';
import { useFilteredSearchPeopleQuery } from '@/people/hooks/useFilteredSearchPeopleQuery'; import { useFilteredSearchPeopleQuery } from '@/people/hooks/useFilteredSearchPeopleQuery';
import { MultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect'; import { MultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
import { useInlineCell } from '@/ui/object/record-inline-cell/hooks/useInlineCell'; import { useInlineCell } from '@/ui/object/record-inline-cell/hooks/useInlineCell';
import { Activity, ActivityTarget } from '~/generated/graphql';
import { assertNotNull } from '~/utils/assert'; import { assertNotNull } from '~/utils/assert';
type ActivityRelationEditableFieldEditModeProps = { type ActivityRelationEditableFieldEditModeProps = {

View File

@ -1,16 +0,0 @@
import { gql } from '@apollo/client';
export const ACTIVITY_WITH_TARGETS = gql`
fragment ActivityWithTargets on Activity {
id
createdAt
updatedAt
activityTargets {
id
createdAt
updatedAt
companyId
personId
}
}
`;

View File

@ -1,54 +0,0 @@
import { gql } from '@apollo/client';
export const ACTIVITY_QUERY_FRAGMENT = gql`
fragment ActivityQueryFragment on Activity {
id
createdAt
title
body
type
completedAt
dueAt
assignee {
id
firstName
lastName
displayName
avatarUrl
}
author {
id
firstName
lastName
displayName
}
comments {
id
body
createdAt
updatedAt
author {
id
displayName
firstName
lastName
avatarUrl
}
}
activityTargets {
id
companyId
personId
company {
id
name
domainName
}
person {
id
displayName
avatarUrl
}
}
}
`;

View File

@ -1,18 +0,0 @@
import { gql } from '@apollo/client';
export const ACTIVITY_UPDATE_FRAGMENT = gql`
fragment ActivityUpdateParts on Activity {
id
body
title
type
completedAt
dueAt
assignee {
id
firstName
lastName
displayName
}
}
`;

View File

@ -1,15 +0,0 @@
import { gql } from '@apollo/client';
export const ADD_ACTIVITY_TARGETS = gql`
mutation AddActivityTargetsOnActivity(
$activityId: String!
$activityTargetInputs: [ActivityTargetCreateManyActivityInput!]!
) {
updateOneActivity(
where: { id: $activityId }
data: { activityTargets: { createMany: { data: $activityTargetInputs } } }
) {
...ActivityWithTargets
}
}
`;

View File

@ -1,30 +0,0 @@
import { gql } from '@apollo/client';
export const CREATE_ACTIVITY_WITH_COMMENT = gql`
mutation CreateActivity($data: ActivityCreateInput!) {
createOneActivity(data: $data) {
id
createdAt
updatedAt
authorId
type
activityTargets {
id
createdAt
updatedAt
activityId
companyId
personId
}
comments {
id
createdAt
updatedAt
body
author {
id
}
}
}
}
`;

View File

@ -1,33 +0,0 @@
import { gql } from '@apollo/client';
export const CREATE_COMMENT = gql`
mutation CreateComment(
$commentId: String!
$commentText: String!
$authorId: String!
$activityId: String!
$createdAt: DateTime!
) {
createOneComment(
data: {
id: $commentId
createdAt: $createdAt
body: $commentText
author: { connect: { id: $authorId } }
activity: { connect: { id: $activityId } }
}
) {
id
createdAt
body
author {
id
displayName
firstName
lastName
avatarUrl
}
activityId
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const DELETE_ACTIVITY = gql`
mutation DeleteActivity($activityId: String!) {
deleteManyActivities(where: { id: { equals: $activityId } }) {
count
}
}
`;

View File

@ -1,18 +0,0 @@
import { gql } from '@apollo/client';
export const REMOVE_ACTIVITY_TARGETS = gql`
mutation RemoveActivityTargetsOnActivity(
$activityId: String!
$activityTargetIds: [String!]!
) {
updateOneActivity(
where: { id: $activityId }
data: {
activityTargets: { deleteMany: { id: { in: $activityTargetIds } } }
}
) {
...ActivityWithTargets
}
}
`;
//

View File

@ -1,12 +0,0 @@
import { gql } from '@apollo/client';
export const UPDATE_ACTIVITY = gql`
mutation UpdateActivity(
$where: ActivityWhereUniqueInput!
$data: ActivityUpdateInput!
) {
updateOneActivity(where: $where, data: $data) {
...ActivityUpdateParts
}
}
`;

View File

@ -1,17 +0,0 @@
import { gql } from '@apollo/client';
export const UPLOAD_ATTACHMENT = gql`
mutation UploadAttachment(
$file: Upload!
$activityId: String!
$companyId: String!
$personId: String!
) {
uploadAttachment(
file: $file
activityId: $activityId
companyId: $companyId
personId: $personId
)
}
`;

View File

@ -1,12 +0,0 @@
import { gql } from '@apollo/client';
export const GET_ACTIVITIES = gql`
query GetActivities(
$where: ActivityWhereInput!
$orderBy: [ActivityOrderByWithRelationInput!]
) {
findManyActivities(orderBy: $orderBy, where: $where) {
...ActivityQueryFragment
}
}
`;

View File

@ -1,24 +0,0 @@
import { gql } from '@apollo/client';
export const GET_ACTIVITIES_BY_TARGETS = gql`
query GetActivitiesByTargets(
$activityTargetIds: [String!]!
$orderBy: [ActivityOrderByWithRelationInput!]
) {
findManyActivities(
orderBy: $orderBy
where: {
activityTargets: {
some: {
OR: [
{ personId: { in: $activityTargetIds } }
{ companyId: { in: $activityTargetIds } }
]
}
}
}
) {
...ActivityQueryFragment
}
}
`;

View File

@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const GET_ACTIVITY = gql`
query GetActivity($activityId: String!) {
findManyActivities(where: { id: { equals: $activityId } }) {
...ActivityQueryFragment
}
}
`;

View File

@ -1,17 +1,10 @@
import { getOperationName } from '@apollo/client/utilities';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { GET_COMPANIES } from '@/companies/graphql/queries/getCompanies'; import { Activity } from '@/activities/types/Activity';
import { GET_PEOPLE } from '@/people/graphql/queries/getPeople'; import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
Activity, import { useDeleteOneObjectRecord } from '@/object-record/hooks/useDeleteOneObjectRecord';
ActivityTarget,
useAddActivityTargetsOnActivityMutation,
useRemoveActivityTargetsOnActivityMutation,
} from '~/generated/graphql';
import { GET_ACTIVITY } from '../graphql/queries/getActivity';
import { ActivityTargetableEntityType } from '../types/ActivityTargetableEntity';
import { ActivityTargetableEntityForSelect } from '../types/ActivityTargetableEntityForSelect'; import { ActivityTargetableEntityForSelect } from '../types/ActivityTargetableEntityForSelect';
export const useHandleCheckableActivityTargetChange = ({ export const useHandleCheckableActivityTargetChange = ({
@ -23,23 +16,12 @@ export const useHandleCheckableActivityTargetChange = ({
> | null; > | null;
}; };
}) => { }) => {
const [addActivityTargetsOnActivity] = const { createOneObject } = useCreateOneObjectRecord({
useAddActivityTargetsOnActivityMutation({ objectNamePlural: 'activityTargetV2',
refetchQueries: [ });
getOperationName(GET_COMPANIES) ?? '', const { deleteOneObject } = useDeleteOneObjectRecord({
getOperationName(GET_PEOPLE) ?? '', objectNamePlural: 'activityTargetV2',
getOperationName(GET_ACTIVITY) ?? '', });
],
});
const [removeActivityTargetsOnActivity] =
useRemoveActivityTargetsOnActivityMutation({
refetchQueries: [
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_ACTIVITY) ?? '',
],
});
return async ( return async (
entityValues: Record<string, boolean>, entityValues: Record<string, boolean>,
@ -59,24 +41,19 @@ export const useHandleCheckableActivityTargetChange = ({
({ id }) => entityValues[id] && !currentEntityIds.includes(id), ({ id }) => entityValues[id] && !currentEntityIds.includes(id),
); );
if (entitiesToAdd.length) if (entitiesToAdd.length) {
await addActivityTargetsOnActivity({ entitiesToAdd.map((entity) => {
variables: { createOneObject?.({
activityId: activity.id, activityId: activity.id,
activityTargetInputs: entitiesToAdd.map((entity) => ({ activityTargetInputs: {
id: v4(), id: v4(),
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
companyId: companyId: entity.entityType === 'Company' ? entity.id : null,
entity.entityType === ActivityTargetableEntityType.Company personId: entity.entityType === 'Person' ? entity.id : null,
? entity.id },
: null, });
personId:
entity.entityType === ActivityTargetableEntityType.Person
? entity.id
: null,
})),
},
}); });
}
const activityTargetIdsToDelete = activity.activityTargets const activityTargetIdsToDelete = activity.activityTargets
? activity.activityTargets ? activity.activityTargets
@ -88,12 +65,10 @@ export const useHandleCheckableActivityTargetChange = ({
.map(({ id }) => id) .map(({ id }) => id)
: []; : [];
if (activityTargetIdsToDelete.length) if (activityTargetIdsToDelete.length) {
await removeActivityTargetsOnActivity({ activityTargetIdsToDelete.map((id) => {
variables: { deleteOneObject?.(id);
activityId: activity.id,
activityTargetIds: activityTargetIdsToDelete,
},
}); });
}
}; };
}; };

View File

@ -1,20 +1,15 @@
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { Activity, ActivityType } from '@/activities/types/Activity';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { GET_COMPANIES } from '@/companies/graphql/queries/getCompanies'; import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
import { GET_PEOPLE } from '@/people/graphql/queries/getPeople';
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope'; import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { ActivityType, useCreateActivityMutation } from '~/generated/graphql';
import { GET_ACTIVITIES } from '../graphql/queries/getActivities';
import { GET_ACTIVITIES_BY_TARGETS } from '../graphql/queries/getActivitiesByTarget';
import { GET_ACTIVITY } from '../graphql/queries/getActivity';
import { activityTargetableEntityArrayState } from '../states/activityTargetableEntityArrayState'; import { activityTargetableEntityArrayState } from '../states/activityTargetableEntityArrayState';
import { viewableActivityIdState } from '../states/viewableActivityIdState'; import { viewableActivityIdState } from '../states/viewableActivityIdState';
import { ActivityTargetableEntity } from '../types/ActivityTargetableEntity'; import { ActivityTargetableEntity } from '../types/ActivityTargetableEntity';
@ -22,7 +17,9 @@ import { getRelationData } from '../utils/getRelationData';
export const useOpenCreateActivityDrawer = () => { export const useOpenCreateActivityDrawer = () => {
const { openRightDrawer } = useRightDrawer(); const { openRightDrawer } = useRightDrawer();
const [createActivityMutation] = useCreateActivityMutation(); const { createOneObject } = useCreateOneObjectRecord({
objectNamePlural: 'activitiesV2',
});
const currentUser = useRecoilValue(currentUserState); const currentUser = useRecoilValue(currentUserState);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const setHotkeyScope = useSetHotkeyScope(); const setHotkeyScope = useSetHotkeyScope();
@ -43,41 +40,28 @@ export const useOpenCreateActivityDrawer = () => {
}) => { }) => {
const now = new Date().toISOString(); const now = new Date().toISOString();
return createActivityMutation({ createOneObject?.({
variables: { id: v4(),
data: { createdAt: now,
id: v4(), updatedAt: now,
createdAt: now, author: { connect: { id: currentUser?.id ?? '' } },
updatedAt: now, workspaceMemberAuthor: {
author: { connect: { id: currentUser?.id ?? '' } }, connect: { id: currentWorkspaceMember?.id ?? '' },
workspaceMemberAuthor: { },
connect: { id: currentWorkspaceMember?.id ?? '' }, assignee: { connect: { id: assigneeId ?? currentUser?.id ?? '' } },
}, workspaceMemberAssignee: {
assignee: { connect: { id: assigneeId ?? currentUser?.id ?? '' } }, connect: { id: currentWorkspaceMember?.id ?? '' },
workspaceMemberAssignee: { },
connect: { id: currentWorkspaceMember?.id ?? '' }, type: type,
}, activityTargets: {
type: type, createMany: {
activityTargets: { data: targetableEntities ? getRelationData(targetableEntities) : [],
createMany: { skipDuplicates: true,
data: targetableEntities
? getRelationData(targetableEntities)
: [],
skipDuplicates: true,
},
},
}, },
}, },
refetchQueries: [ onCompleted: (data: Activity) => {
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_ACTIVITY) ?? '',
getOperationName(GET_ACTIVITIES_BY_TARGETS) ?? '',
getOperationName(GET_ACTIVITIES) ?? '',
],
onCompleted: (data) => {
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false }); setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
setViewableActivityId(data.createOneActivity.id); setViewableActivityId(data.id);
setActivityTargetableEntityArray(targetableEntities ?? []); setActivityTargetableEntityArray(targetableEntities ?? []);
openRightDrawer(RightDrawerPages.CreateActivity); openRightDrawer(RightDrawerPages.CreateActivity);
}, },

View File

@ -1,7 +1,7 @@
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { ActivityType } from '@/activities/types/Activity';
import { selectedRowIdsSelector } from '@/ui/object/record-table/states/selectors/selectedRowIdsSelector'; import { selectedRowIdsSelector } from '@/ui/object/record-table/states/selectors/selectedRowIdsSelector';
import { ActivityType } from '~/generated/graphql';
import { import {
ActivityTargetableEntity, ActivityTargetableEntity,

View File

@ -4,12 +4,12 @@ import styled from '@emotion/styled';
import { ActivityRelationEditableField } from '@/activities/editable-fields/components/ActivityRelationEditableField'; import { ActivityRelationEditableField } from '@/activities/editable-fields/components/ActivityRelationEditableField';
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { Note } from '@/activities/types/Note';
import { IconComment } from '@/ui/display/icon'; import { IconComment } from '@/ui/display/icon';
import { import {
FieldContext, FieldContext,
GenericFieldContextType, GenericFieldContextType,
} from '@/ui/object/field/contexts/FieldContext'; } from '@/ui/object/field/contexts/FieldContext';
import { Activity, ActivityTarget, Comment } from '~/generated/graphql';
const StyledCard = styled.div<{ isSingleNote: boolean }>` const StyledCard = styled.div<{ isSingleNote: boolean }>`
align-items: flex-start; align-items: flex-start;
@ -76,13 +76,7 @@ export const NoteCard = ({
note, note,
isSingleNote, isSingleNote,
}: { }: {
note: Pick< note: Note;
Activity,
'id' | 'title' | 'body' | 'type' | 'completedAt' | 'dueAt'
> & {
activityTargets?: Array<Pick<ActivityTarget, 'id'>> | null;
comments?: Array<Pick<Comment, 'id'>> | null;
};
isSingleNote: boolean; isSingleNote: boolean;
}) => { }) => {
const theme = useTheme(); const theme = useTheme();

View File

@ -1,13 +1,13 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { NoteForList } from '../../types/NoteForList'; import { Note } from '@/activities/types/Note';
import { NoteCard } from './NoteCard'; import { NoteCard } from './NoteCard';
type NoteListProps = { type NoteListProps = {
title: string; title: string;
notes: NoteForList[]; notes: Note[];
button?: ReactElement | false; button?: ReactElement | false;
}; };

View File

@ -1,27 +1,25 @@
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql'; import { Note } from '@/activities/types/Note';
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 { data: notesData } = useGetActivitiesQuery({ const { objects: notes } = useFindManyObjectRecords({
variables: { objectNamePlural: 'activitiesV2',
where: { filter: {
type: { equals: ActivityType.Note }, type: { equals: 'None' },
activityTargets: { activityTargets: {
some: { some: {
OR: [ OR: [
{ companyId: { equals: entity.id } }, { companyId: { equals: entity.id } },
{ personId: { equals: entity.id } }, { personId: { equals: entity.id } },
], ],
},
}, },
}, },
}, },
}); });
const notes = notesData?.findManyActivities;
return { return {
notes, notes: notes as Note[],
}; };
}; };

View File

@ -1,33 +1,23 @@
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { GET_ACTIVITIES } from '@/activities/graphql/queries/getActivities'; import { useDeleteOneObjectRecord } from '@/object-record/hooks/useDeleteOneObjectRecord';
import { GET_ACTIVITIES_BY_TARGETS } from '@/activities/graphql/queries/getActivitiesByTarget';
import { GET_COMPANIES } from '@/companies/graphql/queries/getCompanies';
import { GET_PEOPLE } from '@/people/graphql/queries/getPeople';
import { IconTrash } from '@/ui/display/icon'; import { IconTrash } from '@/ui/display/icon';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState'; import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState';
import { useDeleteActivityMutation } from '~/generated/graphql';
type ActivityActionBarProps = { type ActivityActionBarProps = {
activityId: string; activityId: string;
}; };
export const ActivityActionBar = ({ activityId }: ActivityActionBarProps) => { export const ActivityActionBar = ({ activityId }: ActivityActionBarProps) => {
const [deleteActivityMutation] = useDeleteActivityMutation();
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState); const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
const { deleteOneObject } = useDeleteOneObjectRecord({
objectNamePlural: 'activitiesV2',
});
const deleteActivity = () => { const deleteActivity = () => {
deleteActivityMutation({ deleteOneObject?.(activityId);
variables: { activityId },
refetchQueries: [
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_ACTIVITIES_BY_TARGETS) ?? '',
getOperationName(GET_ACTIVITIES) ?? '',
],
});
setIsRightDrawerOpen(false); setIsRightDrawerOpen(false);
}; };

View File

@ -3,8 +3,9 @@ import styled from '@emotion/styled';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { ActivityEditor } from '@/activities/components/ActivityEditor'; import { ActivityEditor } from '@/activities/components/ActivityEditor';
import { Activity } from '@/activities/types/Activity';
import { useFindOneObjectRecord } from '@/object-record/hooks/useFindOneObjectRecord';
import { entityFieldsFamilyState } from '@/ui/object/field/states/entityFieldsFamilyState'; import { entityFieldsFamilyState } from '@/ui/object/field/states/entityFieldsFamilyState';
import { useGetActivityQuery } from '~/generated/graphql';
import '@blocknote/core/style.css'; import '@blocknote/core/style.css';
@ -33,18 +34,15 @@ export const RightDrawerActivity = ({
entityFieldsFamilyState(activityId), entityFieldsFamilyState(activityId),
); );
const { data } = useGetActivityQuery({ const { object: activity } = useFindOneObjectRecord({
variables: { objectNameSingular: 'activityId',
activityId: activityId ?? '', objectRecordId: activityId,
},
skip: !activityId, skip: !activityId,
onCompleted: (data) => { onCompleted: (activity: Activity) => {
setEntityFields(data?.findManyActivities[0] ?? {}); setEntityFields(activity ?? {});
}, },
}); });
const activity = data?.findManyActivities[0];
if (!activity) { if (!activity) {
return <></>; return <></>;
} }

View File

@ -8,8 +8,6 @@ import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWith
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedTasks } from '~/testing/mock-data/activities'; import { mockedTasks } from '~/testing/mock-data/activities';
import { ActivityTargetableEntityType } from '../../types/ActivityTargetableEntity';
const meta: Meta<typeof TaskGroups> = { const meta: Meta<typeof TaskGroups> = {
title: 'Modules/Activity/TaskGroups', title: 'Modules/Activity/TaskGroups',
component: TaskGroups, component: TaskGroups,
@ -37,7 +35,7 @@ export const WithTasks: Story = {
args: { args: {
entity: { entity: {
id: mockedTasks[0].authorId, id: mockedTasks[0].authorId,
type: ActivityTargetableEntityType.Person, type: 'Person',
}, },
}, },
}; };

View File

@ -1,13 +1,13 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { TaskForList } from '@/activities/types/TaskForList'; import { Activity } from '@/activities/types/Activity';
import { TaskRow } from './TaskRow'; import { TaskRow } from './TaskRow';
type TaskListProps = { type TaskListProps = {
title?: string; title?: string;
tasks: TaskForList[]; tasks: Omit<Activity, 'assigneeId'>[];
button?: ReactElement | false; button?: ReactElement | false;
}; };

View File

@ -3,12 +3,12 @@ import styled from '@emotion/styled';
import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips'; import { ActivityTargetChips } from '@/activities/components/ActivityTargetChips';
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { Activity } from '@/activities/types/Activity';
import { IconCalendar, IconComment } from '@/ui/display/icon'; import { IconCalendar, IconComment } from '@/ui/display/icon';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip'; import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { Checkbox, CheckboxShape } from '@/ui/input/components/Checkbox'; import { Checkbox, CheckboxShape } from '@/ui/input/components/Checkbox';
import { beautifyExactDate, hasDatePassed } from '~/utils/date-utils'; import { beautifyExactDate, hasDatePassed } from '~/utils/date-utils';
import { TaskForList } from '../../types/TaskForList';
import { useCompleteTask } from '../hooks/useCompleteTask'; import { useCompleteTask } from '../hooks/useCompleteTask';
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -61,7 +61,7 @@ const StyledFieldsContainer = styled.div`
display: flex; display: flex;
`; `;
export const TaskRow = ({ task }: { task: TaskForList }) => { export const TaskRow = ({ task }: { task: Omit<Activity, 'assigneeId'> }) => {
const theme = useTheme(); const theme = useTheme();
const openActivityRightDrawer = useOpenActivityRightDrawer(); const openActivityRightDrawer = useOpenActivityRightDrawer();

View File

@ -1,44 +1,26 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useApolloClient } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import { Activity, useUpdateActivityMutation } from '~/generated/graphql'; import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { Activity } from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../../graphql/fragments/activityUpdateFragment';
import { GET_ACTIVITIES } from '../../graphql/queries/getActivities';
type Task = Pick<Activity, 'id' | 'completedAt'>; type Task = Pick<Activity, 'id' | 'completedAt'>;
export const useCompleteTask = (task: Task) => { export const useCompleteTask = (task: Task) => {
const [updateActivityMutation] = useUpdateActivityMutation(); const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'activityV2',
const client = useApolloClient();
const cachedTask = client.readFragment({
id: `Activity:${task.id}`,
fragment: ACTIVITY_UPDATE_FRAGMENT,
}); });
const completeTask = useCallback( const completeTask = useCallback(
(value: boolean) => { (value: boolean) => {
const completedAt = value ? new Date().toISOString() : null; const completedAt = value ? new Date().toISOString() : null;
updateActivityMutation({ updateOneObject?.({
variables: { idToUpdate: task.id,
where: { id: task.id }, input: {
data: { completedAt,
completedAt,
},
}, },
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
...cachedTask,
completedAt,
},
},
refetchQueries: [getOperationName(GET_ACTIVITIES) ?? ''],
}); });
}, },
[cachedTask, task.id, updateActivityMutation], [task.id, updateOneObject],
); );
return { return {

View File

@ -3,40 +3,46 @@ import { useRecoilState, useRecoilValue } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause'; import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql'; import { SortOrder } from '~/generated/graphql';
import { ActivityType } from '~/generated-metadata/graphql';
import { parseDate } from '~/utils/date-utils'; import { parseDate } from '~/utils/date-utils';
export const useCurrentUserTaskCount = () => { export const useCurrentUserTaskCount = () => {
const [currentUser] = useRecoilState(currentUserState); const [currentUser] = useRecoilState(currentUserState);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const { data } = useGetActivitiesQuery({ const { objects } = useFindManyObjectRecords({
variables: { objectNamePlural: 'activitiesV2',
where: { filter: {
type: { equals: ActivityType.Task }, type: { equals: ActivityType.Task },
completedAt: { equals: null }, completedAt: { equals: null },
...(currentUser ...(currentUser
? turnFilterIntoWhereClause({ ? turnFilterIntoWhereClause({
fieldMetadataId: 'assigneeId', fieldMetadataId: 'assigneeId',
value: currentUser.id, value: currentUser.id,
operand: ViewFilterOperand.Is, operand: ViewFilterOperand.Is,
displayValue: displayValue:
currentWorkspaceMember?.firstName + currentWorkspaceMember?.firstName +
' ' + ' ' +
currentWorkspaceMember?.lastName, currentWorkspaceMember?.lastName,
displayAvatarUrl: currentWorkspaceMember?.avatarUrl ?? undefined, displayAvatarUrl: currentWorkspaceMember?.avatarUrl ?? undefined,
definition: { definition: {
type: 'ENTITY', type: 'ENTITY',
}, },
}) })
: {}), : {}),
},
}, },
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
}); });
const currentUserDueTaskCount = data?.findManyActivities.filter((task) => { const currentUserDueTaskCount = objects.filter((task) => {
if (!task.dueAt) { if (!task.dueAt) {
return false; return false;
} }

View File

@ -1,9 +1,11 @@
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { Activity } from '@/activities/types/Activity';
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
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 { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause'; import { turnFilterIntoWhereClause } from '@/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause';
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql'; import { SortOrder } from '~/generated/graphql';
import { parseDate } from '~/utils/date-utils'; import { parseDate } from '~/utils/date-utils';
export const useTasks = (entity?: ActivityTargetableEntity) => { export const useTasks = (entity?: ActivityTargetableEntity) => {
@ -22,62 +24,64 @@ export const useTasks = (entity?: ActivityTargetableEntity) => {
} }
: Object.assign({}, turnFilterIntoWhereClause(selectedFilter)); : Object.assign({}, turnFilterIntoWhereClause(selectedFilter));
const { data: completeTasksData } = useGetActivitiesQuery({ const { objects: completeTasksData } = useFindManyObjectRecords({
variables: { objectNamePlural: 'activitiesV2',
where: {
type: { equals: ActivityType.Task },
completedAt: { not: { equals: null } },
...whereFilters,
},
},
skip: !entity && !selectedFilter, skip: !entity && !selectedFilter,
filter: {
type: { equals: 'Task' },
completedAt: { not: { equals: null } },
...whereFilters,
},
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
}); });
const { data: incompleteTaskData } = useGetActivitiesQuery({ const { objects: incompleteTaskData } = useFindManyObjectRecords({
variables: { objectNamePlural: 'activitiesV2',
where: {
type: { equals: ActivityType.Task },
completedAt: { equals: null },
...whereFilters,
},
},
skip: !entity && !selectedFilter, skip: !entity && !selectedFilter,
filter: {
type: { equals: 'Task' },
completedAt: { equals: null },
...whereFilters,
},
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
}); });
const todayOrPreviousTasks = incompleteTaskData?.findManyActivities.filter( const todayOrPreviousTasks = incompleteTaskData?.filter((task) => {
(task) => { if (!task.dueAt) {
if (!task.dueAt) { return false;
return false; }
} const dueDate = parseDate(task.dueAt).toJSDate();
const dueDate = parseDate(task.dueAt).toJSDate(); const today = DateTime.now().endOf('day').toJSDate();
const today = DateTime.now().endOf('day').toJSDate(); return dueDate <= today;
return dueDate <= today; });
},
);
const upcomingTasks = incompleteTaskData?.findManyActivities.filter( const upcomingTasks = incompleteTaskData?.filter((task) => {
(task) => { if (!task.dueAt) {
if (!task.dueAt) { return false;
return false; }
} const dueDate = parseDate(task.dueAt).toJSDate();
const dueDate = parseDate(task.dueAt).toJSDate(); const today = DateTime.now().endOf('day').toJSDate();
const today = DateTime.now().endOf('day').toJSDate(); return dueDate > today;
return dueDate > today; });
},
);
const unscheduledTasks = incompleteTaskData?.findManyActivities.filter( const unscheduledTasks = incompleteTaskData?.filter((task) => {
(task) => { return !task.dueAt;
return !task.dueAt; });
},
);
const completedTasks = completeTasksData?.findManyActivities; const completedTasks = completeTasksData;
return { return {
todayOrPreviousTasks: todayOrPreviousTasks ?? [], todayOrPreviousTasks: (todayOrPreviousTasks ?? []) as Activity[],
upcomingTasks: upcomingTasks ?? [], upcomingTasks: (upcomingTasks ?? []) as Activity[],
unscheduledTasks: unscheduledTasks ?? [], unscheduledTasks: (unscheduledTasks ?? []) as Activity[],
completedTasks: completedTasks ?? [], completedTasks: (completedTasks ?? []) as Activity[],
}; };
}; };

View File

@ -3,14 +3,12 @@ import styled from '@emotion/styled';
import { ActivityCreateButton } from '@/activities/components/ActivityCreateButton'; import { ActivityCreateButton } from '@/activities/components/ActivityCreateButton';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { Activity } from '@/activities/types/Activity';
import { ActivityForDrawer } from '@/activities/types/ActivityForDrawer'; import { ActivityForDrawer } from '@/activities/types/ActivityForDrawer';
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { import { SortOrder } from '~/generated/graphql';
ActivityType,
SortOrder,
useGetActivitiesByTargetsQuery,
} from '~/generated/graphql';
import { TimelineItemsContainer } from './TimelineItemsContainer'; import { TimelineItemsContainer } from './TimelineItemsContainer';
@ -52,20 +50,21 @@ const StyledEmptyTimelineSubTitle = styled.div`
`; `;
export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => { export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => {
const { data: queryResult, loading } = useGetActivitiesByTargetsQuery({ const { objects, loading } = useFindManyObjectRecords({
variables: { objectNamePlural: 'activitiesV2',
activityTargetIds: [entity.id], filter: {
orderBy: [ companyId: { eq: entity.id },
{
createdAt: SortOrder.Desc,
},
],
}, },
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
}); });
const openCreateActivity = useOpenCreateActivityDrawer(); const openCreateActivity = useOpenCreateActivityDrawer();
const activities: ActivityForDrawer[] = queryResult?.findManyActivities ?? []; const activities: ActivityForDrawer[] = (objects ?? []) as Activity[];
if (loading) { if (loading) {
return <></>; return <></>;
@ -79,13 +78,13 @@ export const Timeline = ({ entity }: { entity: ActivityTargetableEntity }) => {
<ActivityCreateButton <ActivityCreateButton
onNoteClick={() => onNoteClick={() =>
openCreateActivity({ openCreateActivity({
type: ActivityType.Note, type: 'Note',
targetableEntities: [entity], targetableEntities: [entity],
}) })
} }
onTaskClick={() => onTaskClick={() =>
openCreateActivity({ openCreateActivity({
type: ActivityType.Task, type: 'Task',
targetableEntities: [entity], targetableEntities: [entity],
}) })
} }

View File

@ -3,10 +3,10 @@ import styled from '@emotion/styled';
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer'; import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { useCompleteTask } from '@/activities/tasks/hooks/useCompleteTask'; import { useCompleteTask } from '@/activities/tasks/hooks/useCompleteTask';
import { Activity } from '@/activities/types/Activity';
import { IconNotes } from '@/ui/display/icon'; import { IconNotes } from '@/ui/display/icon';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip'; import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { Activity, User } from '~/generated/graphql';
import { import {
beautifyExactDateTime, beautifyExactDateTime,
beautifyPastDateRelativeToNow, beautifyPastDateRelativeToNow,
@ -119,9 +119,19 @@ const StyledTimelineItemContainer = styled.div`
type TimelineActivityProps = { type TimelineActivityProps = {
activity: Pick< activity: Pick<
Activity, Activity,
'id' | 'title' | 'body' | 'createdAt' | 'completedAt' | 'type' | 'id'
> & { author: Pick<Activity['author'], 'displayName'> } & { | 'title'
assignee?: Pick<User, 'id' | 'displayName'> | null; | 'body'
| 'createdAt'
| 'completedAt'
| 'type'
| 'comments'
| 'dueAt'
> & { author: Pick<Activity['author'], 'firstName' | 'lastName'> } & {
assignee?: Pick<
Activity['author'],
'id' | 'firstName' | 'lastName' | 'avatarUrl'
> | null;
}; };
}; };
@ -140,7 +150,9 @@ export const TimelineActivity = ({ activity }: TimelineActivityProps) => {
<IconNotes /> <IconNotes />
</StyledIconContainer> </StyledIconContainer>
<StyledItemTitleContainer> <StyledItemTitleContainer>
<span>{activity.author.displayName}</span> <span>
{activity.author.firstName + ' ' + activity.author.lastName}
</span>
created a {activity.type.toLowerCase()} created a {activity.type.toLowerCase()}
</StyledItemTitleContainer> </StyledItemTitleContainer>
<StyledItemTitleDate id={`id-${activity.id}`}> <StyledItemTitleDate id={`id-${activity.id}`}>

View File

@ -2,13 +2,17 @@ import { isNonEmptyArray } from '@apollo/client/utilities';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import CommentCounter from '@/activities/comment/CommentCounter'; import CommentCounter from '@/activities/comment/CommentCounter';
import { Activity } from '@/activities/types/Activity';
import { UserChip } from '@/users/components/UserChip'; import { UserChip } from '@/users/components/UserChip';
import { Activity, User } from '~/generated/graphql'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { beautifyExactDate } from '~/utils/date-utils'; import { beautifyExactDate } from '~/utils/date-utils';
type TimelineActivityCardFooterProps = { type TimelineActivityCardFooterProps = {
activity: Pick<Activity, 'id' | 'dueAt' | 'comments'> & { activity: Pick<Activity, 'id' | 'dueAt' | 'comments'> & {
assignee?: Pick<User, 'id' | 'displayName' | 'avatarUrl'> | null; assignee?: Pick<
WorkspaceMember,
'id' | 'firstName' | 'lastName' | 'avatarUrl'
> | null;
}; };
}; };
@ -43,7 +47,11 @@ export const TimelineActivityCardFooter = ({
{activity.assignee && ( {activity.assignee && (
<UserChip <UserChip
id={activity.assignee.id} id={activity.assignee.id}
name={activity.assignee.displayName ?? ''} name={
activity.assignee.firstName +
' ' +
activity.assignee.lastName ?? ''
}
pictureUrl={activity.assignee.avatarUrl ?? ''} pictureUrl={activity.assignee.avatarUrl ?? ''}
/> />
)} )}

View File

@ -1,8 +1,8 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { ActivityType } from '@/activities/types/Activity';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip'; import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import { Checkbox, CheckboxShape } from '@/ui/input/components/Checkbox'; import { Checkbox, CheckboxShape } from '@/ui/input/components/Checkbox';
import { ActivityType } from '~/generated/graphql';
const StyledTitleContainer = styled.div` const StyledTitleContainer = styled.div`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
@ -44,7 +44,7 @@ export const TimelineActivityTitle = ({
onCompletionChange, onCompletionChange,
}: TimelineActivityTitleProps) => ( }: TimelineActivityTitleProps) => (
<StyledTitleContainer> <StyledTitleContainer>
{type === ActivityType.Task && ( {type === 'Task' && (
<StyledCheckboxContainer <StyledCheckboxContainer
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -55,10 +55,7 @@ export const TimelineActivityTitle = ({
<Checkbox checked={completed ?? false} shape={CheckboxShape.Rounded} /> <Checkbox checked={completed ?? false} shape={CheckboxShape.Rounded} />
</StyledCheckboxContainer> </StyledCheckboxContainer>
)} )}
<StyledTitleText <StyledTitleText completed={completed} hasCheckbox={type === 'Task'}>
completed={completed}
hasCheckbox={type === ActivityType.Task}
>
<OverflowingTextWithTooltip text={title ? title : 'Task title'} /> <OverflowingTextWithTooltip text={title ? title : 'Task title'} />
</StyledTitleText> </StyledTitleText>
</StyledTitleContainer> </StyledTitleContainer>

View File

@ -0,0 +1,23 @@
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { Comment } from '@/activities/types/Comment';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
export type ActivityType = 'Task' | 'Note';
export type Activity = {
__typename: 'Activity';
id: string;
createdAt: string;
updatedAt: string;
completedAt: string | null;
dueAt: string | null;
activityTargets: ActivityTarget[];
type: ActivityType;
title: string;
body: string;
author: WorkspaceMember;
authorId: string;
assignee: WorkspaceMember | null;
assigneeId: string | null;
comments: Comment[];
};

View File

@ -1,4 +1,3 @@
import { GetActivitiesByTargetsQuery } from '~/generated/graphql'; import { Activity } from '@/activities/types/Activity';
export type ActivityForDrawer = export type ActivityForDrawer = Activity;
GetActivitiesByTargetsQuery['findManyActivities'][0];

View File

@ -0,0 +1,14 @@
import { Activity } from '@/activities/types/Activity';
import { Company, Person } from '~/generated-metadata/graphql';
export type ActivityTarget = {
id: string;
createdAt: string;
updatedAt: string;
companyId: string | null;
personId: string | null;
activity: Pick<Activity, 'id' | 'createdAt' | 'updatedAt'>;
person?: Pick<Person, 'id' | 'firstName' | 'lastName' | 'avatarUrl'> | null;
company?: Pick<Company, 'id' | 'name' | 'domainName'> | null;
[key: string]: any;
};

View File

@ -1,7 +1,4 @@
export enum ActivityTargetableEntityType { export type ActivityTargetableEntityType = 'Person' | 'Company';
Person = 'Person',
Company = 'Company',
}
export type ActivityTargetableEntity = { export type ActivityTargetableEntity = {
id: string; id: string;

View File

@ -0,0 +1,10 @@
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
export type Comment = {
id: string;
createdAt: string;
body: string;
updatedAt: string;
activityId: string;
author: WorkspaceMember;
};

View File

@ -1,3 +0,0 @@
import { ActivityForDrawer } from './ActivityForDrawer';
export type CommentForDrawer = NonNullable<ActivityForDrawer['comments']>[0];

View File

@ -0,0 +1,5 @@
import { Activity } from '@/activities/types/Activity';
export type Note = Activity & {
type: 'Note';
};

View File

@ -1,3 +0,0 @@
import { GetActivitiesQuery } from '~/generated/graphql';
export type NoteForList = GetActivitiesQuery['findManyActivities'][0];

View File

@ -0,0 +1,5 @@
import { Activity } from '@/activities/types/Activity';
export type Task = Activity & {
type: 'Task';
};

View File

@ -1,3 +0,0 @@
import { GetActivitiesQuery } from '~/generated/graphql';
export type TaskForList = GetActivitiesQuery['findManyActivities'][0];

View File

@ -2,10 +2,7 @@ import { v4 } from 'uuid';
import { ActivityTargetCreateManyActivityInput } from '~/generated/graphql'; import { ActivityTargetCreateManyActivityInput } from '~/generated/graphql';
import { import { ActivityTargetableEntity } from '../types/ActivityTargetableEntity';
ActivityTargetableEntity,
ActivityTargetableEntityType,
} from '../types/ActivityTargetableEntity';
export const getRelationData = ( export const getRelationData = (
entities: ActivityTargetableEntity[], entities: ActivityTargetableEntity[],
@ -15,24 +12,16 @@ export const getRelationData = (
const relationData: ActivityTargetCreateManyActivityInput[] = []; const relationData: ActivityTargetCreateManyActivityInput[] = [];
for (const entity of entities ?? []) { for (const entity of entities ?? []) {
relationData.push({ relationData.push({
companyId: companyId: entity.type === 'Company' ? entity.id : null,
entity.type === ActivityTargetableEntityType.Company ? entity.id : null, personId: entity.type === 'Person' ? entity.id : null,
personId:
entity.type === ActivityTargetableEntityType.Person ? entity.id : null,
id: v4(), id: v4(),
createdAt: now, createdAt: now,
}); });
if (entity.relatedEntities) { if (entity.relatedEntities) {
for (const relatedEntity of entity.relatedEntities ?? []) { for (const relatedEntity of entity.relatedEntities ?? []) {
relationData.push({ relationData.push({
companyId: companyId: relatedEntity.type === 'Company' ? relatedEntity.id : null,
relatedEntity.type === ActivityTargetableEntityType.Company personId: relatedEntity.type === 'Person' ? relatedEntity.id : null,
? relatedEntity.id
: null,
personId:
relatedEntity.type === ActivityTargetableEntityType.Person
? relatedEntity.id
: null,
id: v4(), id: v4(),
createdAt: now, createdAt: now,
}); });

View File

@ -1,8 +1,7 @@
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity'; import { ActivityType } from '@/activities/types/Activity';
import { ActivityType } from '~/generated/graphql';
export const useCreateActivityForCompany = () => { export const useCreateActivityForCompany = () => {
const openCreateActivityRightDrawer = const openCreateActivityRightDrawer =
@ -10,7 +9,7 @@ export const useCreateActivityForCompany = () => {
return useRecoilCallback( return useRecoilCallback(
() => (type: ActivityType) => { () => (type: ActivityType) => {
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company); openCreateActivityRightDrawer(type, 'Company');
}, },
[openCreateActivityRightDrawer], [openCreateActivityRightDrawer],
); );

View File

@ -1,4 +1,3 @@
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { useSearchCompanyQuery } from '~/generated/graphql'; import { useSearchCompanyQuery } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils'; import { getLogoUrlFromDomainName } from '~/utils';
@ -23,7 +22,7 @@ export const useFilteredSearchCompanyQuery = ({
orderByField: 'name', orderByField: 'name',
mappingFunction: (company) => ({ mappingFunction: (company) => ({
id: company.id, id: company.id,
entityType: ActivityTargetableEntityType.Company, entityType: 'Company',
name: company.name, name: company.name,
avatarUrl: getLogoUrlFromDomainName(company.domainName), avatarUrl: getLogoUrlFromDomainName(company.domainName),
domainName: company.domainName, domainName: company.domainName,

View File

@ -2,7 +2,6 @@ import { useParams } from 'react-router-dom';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { useFavorites } from '@/favorites/hooks/useFavorites'; import { useFavorites } from '@/favorites/hooks/useFavorites';
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem'; import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
@ -50,7 +49,7 @@ export const RecordShowPage = () => {
); );
const { object } = useFindOneObjectRecord({ const { object } = useFindOneObjectRecord({
objectMetadataId: objectMetadataId, objectRecordId: objectMetadataId,
objectNameSingular, objectNameSingular,
onCompleted: (data) => { onCompleted: (data) => {
setEntityFields(data); setEntityFields(data);
@ -133,7 +132,7 @@ export const RecordShowPage = () => {
key="add" key="add"
entity={{ entity={{
id: object.id, id: object.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}} }}
/> />
</PageHeader> </PageHeader>
@ -185,7 +184,7 @@ export const RecordShowPage = () => {
<ShowPageRightContainer <ShowPageRightContainer
entity={{ entity={{
id: object.id, id: object.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}} }}
timeline timeline
tasks tasks

View File

@ -7,11 +7,13 @@ export const useFindOneObjectRecord = <
ObjectType extends { id: string } & Record<string, any>, ObjectType extends { id: string } & Record<string, any>,
>({ >({
objectNameSingular, objectNameSingular,
objectMetadataId, objectRecordId,
onCompleted, onCompleted,
skip,
}: Pick<ObjectMetadataItemIdentifier, 'objectNameSingular'> & { }: Pick<ObjectMetadataItemIdentifier, 'objectNameSingular'> & {
objectMetadataId: string | undefined; objectRecordId: string | undefined;
onCompleted?: (data: ObjectType) => void; onCompleted?: (data: ObjectType) => void;
skip?: boolean;
}) => { }) => {
const { foundObjectMetadataItem, objectNotFoundInMetadata, findOneQuery } = const { foundObjectMetadataItem, objectNotFoundInMetadata, findOneQuery } =
useFindOneObjectMetadataItem({ useFindOneObjectMetadataItem({
@ -20,11 +22,11 @@ export const useFindOneObjectRecord = <
const { data, loading, error } = useQuery< const { data, loading, error } = useQuery<
{ [nameSingular: string]: ObjectType }, { [nameSingular: string]: ObjectType },
{ objectMetadataId: string } { objectRecordId: string }
>(findOneQuery, { >(findOneQuery, {
skip: !foundObjectMetadataItem || !objectMetadataId, skip: !foundObjectMetadataItem || !objectRecordId || skip,
variables: { variables: {
objectMetadataId: objectMetadataId ?? '', objectRecordId: objectRecordId ?? '',
}, },
onCompleted: (data) => { onCompleted: (data) => {
if (onCompleted && objectNameSingular) { if (onCompleted && objectNameSingular) {

View File

@ -1,10 +1,7 @@
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds'; import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
import { import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
ActivityTargetableEntity,
ActivityTargetableEntityType,
} from '@/activities/types/ActivityTargetableEntity';
import { entityFieldsFamilyState } from '@/ui/object/field/states/entityFieldsFamilyState'; import { entityFieldsFamilyState } from '@/ui/object/field/states/entityFieldsFamilyState';
import { selectedRowIdsSelector } from '@/ui/object/record-table/states/selectors/selectedRowIdsSelector'; import { selectedRowIdsSelector } from '@/ui/object/record-table/states/selectors/selectedRowIdsSelector';
import { ActivityType, Person } from '~/generated/graphql'; import { ActivityType, Person } from '~/generated/graphql';
@ -30,16 +27,12 @@ export const useCreateActivityForPeople = () => {
) { ) {
relatedEntites.push({ relatedEntites.push({
id: person.company.id, id: person.company.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}); });
} }
} }
openCreateActivityRightDrawer( openCreateActivityRightDrawer(type, 'Person', relatedEntites);
type,
ActivityTargetableEntityType.Person,
relatedEntites,
);
}, },
[openCreateActivityRightDrawer], [openCreateActivityRightDrawer],
); );

View File

@ -1,4 +1,3 @@
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { ActivityTargetableEntityForSelect } from '@/activities/types/ActivityTargetableEntityForSelect'; import { ActivityTargetableEntityForSelect } from '@/activities/types/ActivityTargetableEntityForSelect';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { useSearchPeopleQuery } from '~/generated/graphql'; import { useSearchPeopleQuery } from '~/generated/graphql';
@ -25,7 +24,7 @@ export const useFilteredSearchPeopleQuery = ({
mappingFunction: (entity) => mappingFunction: (entity) =>
({ ({
id: entity.id, id: entity.id,
entityType: ActivityTargetableEntityType.Person, entityType: 'Person',
name: `${entity.firstName} ${entity.lastName}`, name: `${entity.firstName} ${entity.lastName}`,
avatarUrl: entity.avatarUrl, avatarUrl: entity.avatarUrl,
avatarType: 'rounded', avatarType: 'rounded',

View File

@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { CompanyTeam } from '@/companies/components/CompanyTeam'; 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';
@ -69,7 +68,7 @@ export const CompanyShow = () => {
key="add" key="add"
entity={{ entity={{
id: company.id, id: company.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}} }}
/> />
</PageHeader> </PageHeader>
@ -113,7 +112,7 @@ export const CompanyShow = () => {
<ShowPageRightContainer <ShowPageRightContainer
entity={{ entity={{
id: company.id, id: company.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}} }}
timeline timeline
tasks tasks

View File

@ -4,9 +4,6 @@ import { Meta, StoryObj } from '@storybook/react';
import { fireEvent, within } from '@storybook/testing-library'; import { fireEvent, within } from '@storybook/testing-library';
import { graphql } from 'msw'; import { graphql } from 'msw';
import { CREATE_ACTIVITY_WITH_COMMENT } from '@/activities/graphql/mutations/createActivityWithComment';
import { GET_ACTIVITIES_BY_TARGETS } from '@/activities/graphql/queries/getActivitiesByTarget';
import { GET_ACTIVITY } from '@/activities/graphql/queries/getActivity';
import { UPDATE_ONE_COMPANY } from '@/companies/graphql/mutations/updateOneCompany'; import { UPDATE_ONE_COMPANY } from '@/companies/graphql/mutations/updateOneCompany';
import { GET_COMPANY } from '@/companies/graphql/queries/getCompany'; import { GET_COMPANY } from '@/companies/graphql/queries/getCompany';
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
@ -16,7 +13,6 @@ import {
PageDecoratorArgs, PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator'; } from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks'; import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedActivities, mockedTasks } from '~/testing/mock-data/activities';
import { mockedCompaniesData } from '~/testing/mock-data/companies'; import { mockedCompaniesData } from '~/testing/mock-data/companies';
import { CompanyShow } from '../CompanyShow'; import { CompanyShow } from '../CompanyShow';
@ -32,19 +28,6 @@ const meta: Meta<PageDecoratorArgs> = {
parameters: { parameters: {
msw: [ msw: [
...graphqlMocks, ...graphqlMocks,
graphql.query(
getOperationName(GET_ACTIVITIES_BY_TARGETS) ?? '',
(req, res, ctx) => {
return res(
ctx.data({
findManyActivities:
req?.variables?.where?.type?.equals === 'Task'
? mockedTasks
: mockedActivities,
}),
);
},
),
graphql.query(getOperationName(GET_COMPANY) ?? '', (req, res, ctx) => { graphql.query(getOperationName(GET_COMPANY) ?? '', (req, res, ctx) => {
return res( return res(
ctx.data({ ctx.data({
@ -90,23 +73,6 @@ export const EditNoteByAddButton: Story = {
parameters: { parameters: {
msw: [ msw: [
...meta.parameters?.msw, ...meta.parameters?.msw,
graphql.mutation(
getOperationName(CREATE_ACTIVITY_WITH_COMMENT) ?? '',
(req, res, ctx) => {
return res(
ctx.data({
createOneActivity: mockedActivities[0],
}),
);
},
),
graphql.query(getOperationName(GET_ACTIVITY) ?? '', (req, res, ctx) => {
return res(
ctx.data({
findManyActivities: [mockedActivities[0]],
}),
);
}),
graphql.mutation( graphql.mutation(
getOperationName(UPDATE_ONE_COMPANY) ?? '', getOperationName(UPDATE_ONE_COMPANY) ?? '',
(req, res, ctx) => { (req, res, ctx) => {
@ -145,23 +111,6 @@ export const NoteTab: Story = {
parameters: { parameters: {
msw: [ msw: [
...meta.parameters?.msw, ...meta.parameters?.msw,
graphql.mutation(
getOperationName(CREATE_ACTIVITY_WITH_COMMENT) ?? '',
(req, res, ctx) => {
return res(
ctx.data({
createOneActivity: mockedActivities[0],
}),
);
},
),
graphql.query(getOperationName(GET_ACTIVITY) ?? '', (req, res, ctx) => {
return res(
ctx.data({
findManyActivities: [mockedActivities[0]],
}),
);
}),
graphql.mutation( graphql.mutation(
getOperationName(UPDATE_ONE_COMPANY) ?? '', getOperationName(UPDATE_ONE_COMPANY) ?? '',
(req, res, ctx) => { (req, res, ctx) => {
@ -207,23 +156,6 @@ export const TaskTab: Story = {
parameters: { parameters: {
msw: [ msw: [
...meta.parameters?.msw, ...meta.parameters?.msw,
graphql.mutation(
getOperationName(CREATE_ACTIVITY_WITH_COMMENT) ?? '',
(req, res, ctx) => {
return res(
ctx.data({
createOneActivity: mockedTasks[0],
}),
);
},
),
graphql.query(getOperationName(GET_ACTIVITY) ?? '', (req, res, ctx) => {
return res(
ctx.data({
findManyActivities: [mockedTasks[0]],
}),
);
}),
graphql.mutation( graphql.mutation(
getOperationName(UPDATE_ONE_COMPANY) ?? '', getOperationName(UPDATE_ONE_COMPANY) ?? '',
(req, res, ctx) => { (req, res, ctx) => {

View File

@ -2,7 +2,6 @@ import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { getOperationName } from '@apollo/client/utilities'; import { getOperationName } from '@apollo/client/utilities';
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
import { useFavorites } from '@/favorites/hooks/useFavorites'; 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';
@ -84,12 +83,12 @@ export const PersonShow = () => {
key="add" key="add"
entity={{ entity={{
id: person.id, id: person.id,
type: ActivityTargetableEntityType.Person, type: 'Person',
relatedEntities: person.company?.id relatedEntities: person.company?.id
? [ ? [
{ {
id: person.company?.id, id: person.company?.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}, },
] ]
: undefined, : undefined,
@ -137,12 +136,12 @@ export const PersonShow = () => {
<ShowPageRightContainer <ShowPageRightContainer
entity={{ entity={{
id: person.id ?? '', id: person.id ?? '',
type: ActivityTargetableEntityType.Person, type: 'Person',
relatedEntities: person.company?.id relatedEntities: person.company?.id
? [ ? [
{ {
id: person.company?.id, id: person.company?.id,
type: ActivityTargetableEntityType.Company, type: 'Company',
}, },
] ]
: undefined, : undefined,

View File

@ -1,8 +1,6 @@
import { getOperationName } from '@apollo/client/utilities'; import { getOperationName } from '@apollo/client/utilities';
import { graphql } from 'msw'; import { graphql } from 'msw';
import { CREATE_ACTIVITY_WITH_COMMENT } from '@/activities/graphql/mutations/createActivityWithComment';
import { GET_ACTIVITIES } from '@/activities/graphql/queries/getActivities';
import { CREATE_EVENT } from '@/analytics/graphql/queries/createEvent'; import { CREATE_EVENT } from '@/analytics/graphql/queries/createEvent';
import { GET_CLIENT_CONFIG } from '@/client-config/graphql/queries/getClientConfig'; import { GET_CLIENT_CONFIG } from '@/client-config/graphql/queries/getClientConfig';
import { INSERT_ONE_COMPANY } from '@/companies/graphql/mutations/insertOneCompany'; import { INSERT_ONE_COMPANY } from '@/companies/graphql/mutations/insertOneCompany';
@ -22,7 +20,6 @@ import { GET_API_KEY } from '@/settings/developers/graphql/queries/getApiKey';
import { GET_API_KEYS } from '@/settings/developers/graphql/queries/getApiKeys'; import { GET_API_KEYS } from '@/settings/developers/graphql/queries/getApiKeys';
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
import { import {
ActivityType,
GetCompaniesQuery, GetCompaniesQuery,
GetPeopleQuery, GetPeopleQuery,
GetPersonQuery, GetPersonQuery,
@ -33,7 +30,7 @@ import {
} from '~/generated/graphql'; } from '~/generated/graphql';
import { mockedApiKeys } from '~/testing/mock-data/api-keys'; import { mockedApiKeys } from '~/testing/mock-data/api-keys';
import { mockedActivities, mockedTasks } from './mock-data/activities'; import { mockedActivities } from './mock-data/activities';
import { import {
mockedCompaniesData, mockedCompaniesData,
mockedEmptyCompanyData, mockedEmptyCompanyData,
@ -250,16 +247,6 @@ export const graphqlMocks = [
}), }),
); );
}), }),
graphql.query(getOperationName(GET_ACTIVITIES) ?? '', (req, res, ctx) => {
return res(
ctx.data({
findManyActivities:
req?.variables?.where?.type?.equals === ActivityType.Task
? mockedTasks
: mockedActivities,
}),
);
}),
graphql.query(getOperationName(GET_API_KEY) ?? '', (req, res, ctx) => { graphql.query(getOperationName(GET_API_KEY) ?? '', (req, res, ctx) => {
return res( return res(
@ -275,16 +262,7 @@ export const graphqlMocks = [
}), }),
); );
}), }),
graphql.mutation(
getOperationName(CREATE_ACTIVITY_WITH_COMMENT) ?? '',
(req, res, ctx) => {
return res(
ctx.data({
createOneActivity: mockedTasks[0],
}),
);
},
),
graphql.mutation( graphql.mutation(
getOperationName(INSERT_ONE_COMPANY) ?? '', getOperationName(INSERT_ONE_COMPANY) ?? '',
(req, res, ctx) => { (req, res, ctx) => {

View File

@ -1,12 +1,8 @@
import { import { Activity } from '@/activities/types/Activity';
Activity, import { ActivityTarget } from '@/activities/types/ActivityTarget';
ActivityTarget, import { Comment } from '@/activities/types/Comment';
ActivityType, import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
Comment, import { Company, Person } from '~/generated/graphql';
Company,
Person,
User,
} from '~/generated/graphql';
type MockedActivity = Pick< type MockedActivity = Pick<
Activity, Activity,
@ -21,15 +17,12 @@ type MockedActivity = Pick<
| 'dueAt' | 'dueAt'
| 'completedAt' | 'completedAt'
> & { > & {
author: Pick< author: Pick<WorkspaceMember, 'id' | 'firstName' | 'lastName' | 'avatarUrl'>;
User,
'id' | 'firstName' | 'lastName' | 'displayName' | 'avatarUrl'
>;
assignee: Pick< assignee: Pick<
User, WorkspaceMember,
'id' | 'firstName' | 'lastName' | 'displayName' | 'avatarUrl' 'id' | 'firstName' | 'lastName' | 'avatarUrl'
>; >;
comments: Array<Comment>; comments: Comment[];
activityTargets: Array< activityTargets: Array<
Pick< Pick<
ActivityTarget, ActivityTarget,
@ -54,22 +47,20 @@ export const mockedTasks: Array<MockedActivity> = [
createdAt: '2023-04-26T10:12:42.33625+00:00', createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00', updatedAt: '2023-04-26T10:23:42.33625+00:00',
title: 'My very first task', title: 'My very first task',
type: ActivityType.Task, type: 'Task',
body: null, body: '',
dueAt: '2023-04-26T10:12:42.33625+00:00', dueAt: '2023-04-26T10:12:42.33625+00:00',
completedAt: null, completedAt: null,
author: { author: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
firstName: 'Charles', firstName: 'Charles',
lastName: 'Test', lastName: 'Test',
displayName: 'Charles Test',
avatarUrl: '', avatarUrl: '',
}, },
assignee: { assignee: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
firstName: 'Charles', firstName: 'Charles',
lastName: 'Test', lastName: 'Test',
displayName: 'Charles Test',
avatarUrl: '', avatarUrl: '',
}, },
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
@ -85,22 +76,20 @@ export const mockedActivities: Array<MockedActivity> = [
createdAt: '2023-04-26T10:12:42.33625+00:00', createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00', updatedAt: '2023-04-26T10:23:42.33625+00:00',
title: 'My very first note', title: 'My very first note',
type: ActivityType.Note, type: 'Note',
body: null, body: '',
dueAt: '2023-04-26T10:12:42.33625+00:00', dueAt: '2023-04-26T10:12:42.33625+00:00',
completedAt: null, completedAt: null,
author: { author: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
firstName: 'Charles', firstName: 'Charles',
lastName: 'Test', lastName: 'Test',
displayName: 'Charles Test',
avatarUrl: '', avatarUrl: '',
}, },
assignee: { assignee: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
firstName: 'Charles', firstName: 'Charles',
lastName: 'Test', lastName: 'Test',
displayName: 'Charles Test',
avatarUrl: '', avatarUrl: '',
}, },
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
@ -154,22 +143,20 @@ export const mockedActivities: Array<MockedActivity> = [
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
title: 'Another note', title: 'Another note',
body: null, body: '',
type: ActivityType.Note, type: 'Note',
completedAt: null, completedAt: null,
dueAt: '2029-08-26T10:12:42.33625+00:00', dueAt: '2029-08-26T10:12:42.33625+00:00',
author: { author: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
firstName: 'Charles', firstName: 'Charles',
lastName: 'Test', lastName: 'Test',
displayName: 'Charles Test',
avatarUrl: '', avatarUrl: '',
}, },
assignee: { assignee: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
firstName: 'Charles', firstName: 'Charles',
lastName: 'Test', lastName: 'Test',
displayName: 'Charles Test',
avatarUrl: '', avatarUrl: '',
}, },
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e', authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',