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

View File

@ -656,6 +656,11 @@ export type BoolFilter = {
not?: InputMaybe<NestedBoolFilter>;
};
export type BooleanFieldComparison = {
is?: InputMaybe<Scalars['Boolean']>;
isNot?: InputMaybe<Scalars['Boolean']>;
};
export type ClientConfig = {
__typename?: 'ClientConfig';
authProviders: AuthProviders;
@ -1315,6 +1320,7 @@ export type FieldDeleteResponse = {
isActive?: Maybe<Scalars['Boolean']>;
isCustom?: Maybe<Scalars['Boolean']>;
isNullable?: Maybe<Scalars['Boolean']>;
isSystem?: Maybe<Scalars['Boolean']>;
label?: Maybe<Scalars['String']>;
name?: Maybe<Scalars['String']>;
/** @deprecated Use label name instead */
@ -1357,6 +1363,23 @@ export type FloatFilter = {
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 = {
equals?: InputMaybe<Scalars['Int']>;
gt?: InputMaybe<Scalars['Int']>;
@ -3117,6 +3140,7 @@ export type Field = {
isActive: Scalars['Boolean'];
isCustom: Scalars['Boolean'];
isNullable: Scalars['Boolean'];
isSystem: Scalars['Boolean'];
label: Scalars['String'];
name: Scalars['String'];
/** @deprecated Use label name instead */
@ -3134,6 +3158,15 @@ export type FieldEdge = {
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 = {
__typename?: 'object';
createdAt: Scalars['DateTime'];
@ -3154,6 +3187,7 @@ export type Object = {
export type ObjectFieldsArgs = {
filter?: FieldFilter;
paging?: CursorPaging;
};
@ -3233,94 +3267,6 @@ export type UserV2Edge = {
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<{
type: Scalars['String'];
data: Scalars['JSON'];
@ -3803,88 +3749,6 @@ export type GetWorkspaceMembersQueryVariables = Exact<{
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`
fragment AuthTokenFragment on AuthToken {
token
@ -3982,399 +3846,6 @@ export const UserFieldsFragmentFragmentDoc = gql`
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`
mutation CreateEvent($type: String!, $data: JSON!) {
createEvent(type: $type, data: $data) {

View File

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

View File

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

View File

@ -1,39 +1,34 @@
import { DateTime } from 'luxon';
import { CommentForDrawer } from '@/activities/types/CommentForDrawer';
import { mockedUsersData } from '~/testing/mock-data/users';
const mockUser = mockedUsersData[0];
import { Comment } from '@/activities/types/Comment';
export const mockComment: Pick<
CommentForDrawer,
Comment,
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt'
> = {
id: 'fake_comment_1_uuid',
body: 'Hello, this is a comment.',
author: {
id: 'fake_comment_1_author_uuid',
displayName: mockUser.displayName ?? '',
firstName: mockUser.firstName ?? '',
lastName: mockUser.lastName ?? '',
avatarUrl: mockUser.avatarUrl,
firstName: 'Jony' ?? '',
lastName: 'Ive' ?? '',
avatarUrl: null,
},
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
updatedAt: DateTime.fromFormat('2021-03-13', 'yyyy-MM-dd').toISO() ?? '',
};
export const mockCommentWithLongValues: Pick<
CommentForDrawer,
Comment,
'id' | 'author' | 'createdAt' | 'body' | 'updatedAt'
> = {
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.',
author: {
id: 'fake_comment_2_author_uuid',
displayName: mockUser.displayName + ' with a very long suffix' ?? '',
firstName: mockUser.firstName ?? '',
lastName: mockUser.lastName ?? '',
avatarUrl: mockUser.avatarUrl,
id: 'fake_comment_1_author_uuid',
firstName: 'Jony' ?? '',
lastName: 'Ive' ?? '',
avatarUrl: null,
},
createdAt: DateTime.fromFormat('2021-03-12', '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 { getOperationName } from '@apollo/client/utilities';
import { Activity } from '@/activities/types/Activity';
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import {
Activity,
useGetWorkspaceMembersLazyQuery,
User,
useSearchUserQuery,
useUpdateActivityMutation,
} from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment';
import { GET_ACTIVITIES } from '../graphql/queries/getActivities';
export type ActivityAssigneePickerProps = {
activity: Pick<Activity, 'id'> & {
accountOwner?: Pick<User, 'id' | 'displayName'> | null;
accountOwner?: Pick<
WorkspaceMember,
'id' | 'firstName' | 'lastName'
> | null;
};
onSubmit?: () => void;
onCancel?: () => void;
@ -38,7 +35,9 @@ export const ActivityAssigneePicker = ({
const [relationPickerSearchFilter] = useRecoilScopedState(
relationPickerSearchFilterScopedState,
);
const [updateActivity] = useUpdateActivityMutation();
const { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'ActivityV2',
});
const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery();
const users = useFilteredSearchEntityQuery({
@ -63,12 +62,6 @@ export const ActivityAssigneePicker = ({
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 (
selectedUser: UserForSelect | null | undefined,
) => {
@ -83,28 +76,14 @@ export const ActivityAssigneePicker = ({
})
).data?.workspaceMembers?.[0];
updateActivity({
variables: {
where: { id: activity.id },
data: {
assignee: { connect: { id: selectedUser.id } },
workspaceMemberAssignee: {
connect: { id: workspaceMemberAssignee?.id },
},
updateOneObject?.({
idToUpdate: activity.id,
input: {
assignee: { connect: { id: selectedUser.id } },
workspaceMemberAssignee: {
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 { useApolloClient } from '@apollo/client';
import { BlockNoteEditor } from '@blocknote/core';
import { useBlockNote } from '@blocknote/react';
import styled from '@emotion/styled';
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 { Activity, useUpdateActivityMutation } from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment';
const StyledBlockNoteStyledContainer = styled.div`
width: 100%;
@ -23,15 +21,10 @@ export const ActivityBodyEditor = ({
activity,
onChange,
}: 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 { updateOneObject } = useUpdateOneObjectRecord({
objectNameSingular: 'ActivityV2',
});
useEffect(() => {
if (body) {
@ -42,27 +35,16 @@ export const ActivityBodyEditor = ({
const debounceOnChange = useMemo(() => {
const onInternalChange = (activityBody: string) => {
setBody(activityBody);
updateActivityMutation({
variables: {
where: {
id: activity.id,
},
data: {
body: activityBody,
},
},
optimisticResponse: {
__typename: 'Mutation',
updateOneActivity: {
...cachedActivity,
body: activityBody,
},
updateOneObject?.({
idToUpdate: activity.id,
input: {
body: activityBody,
},
});
};
return debounce(onInternalChange, 200);
}, [updateActivityMutation, activity.id, cachedActivity]);
}, [updateOneObject, activity.id]);
const editor: BlockNoteEditor | null = useBlockNote({
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 { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil';
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 { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
import {
AutosizeTextInput,
AutosizeTextInputVariant,
} from '@/ui/input/components/AutosizeTextInput';
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 = {
activity: Pick<Activity, 'id'> & {
comments: Array<CommentForDrawer>;
comments: Array<CommentType>;
};
scrollableContainerRef: React.RefObject<HTMLDivElement>;
};
@ -63,8 +61,10 @@ export const ActivityComments = ({
activity,
scrollableContainerRef,
}: ActivityCommentsProps) => {
const [createCommentMutation] = useCreateCommentMutation();
const currentUser = useRecoilValue(currentUserState);
const { createOneObject } = useCreateOneObjectRecord({
objectNamePlural: 'commentsV2',
});
if (!currentUser) {
return <></>;
@ -75,21 +75,12 @@ export const ActivityComments = ({
return;
}
createCommentMutation({
variables: {
commentId: v4(),
authorId: currentUser?.id ?? '',
activityId: activity?.id ?? '',
commentText: commentText,
createdAt: new Date().toISOString(),
},
refetchQueries: [getOperationName(GET_ACTIVITY) ?? ''],
onCompleted: () => {
setTimeout(() => {
handleFocus();
}, 100);
},
awaitRefetchQueries: true,
createOneObject?.({
commentId: v4(),
authorId: currentUser?.id ?? '',
activityId: activity?.id ?? '',
commentText: commentText,
createdAt: new Date().toISOString(),
});
};

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
import React, { useMemo } from 'react';
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { IconUserCircle } from '@/ui/display/icon';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
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 { RecordInlineCell } from '@/ui/object/record-inline-cell/components/RecordInlineCell';
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 = {
activity: Pick<Company, 'id' | 'accountOwnerId'> & {
assignee?: Pick<User, 'id' | 'displayName' | 'avatarUrl'> | null;
assignee?: Pick<
WorkspaceMember,
'id' | 'firstName' | 'lastName' | 'avatarUrl'
> | null;
};
};
export const ActivityAssigneeEditableField = ({
activity,
}: 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(
() => ({
entityId: activity.id,
@ -39,7 +67,7 @@ export const ActivityAssigneeEditableField = ({
};
},
} satisfies FieldDefinition<FieldRelationMetadata>,
useUpdateEntityMutation: useUpdateActivityMutation,
useUpdateEntityMutation: useUpdateOneObjectMutation,
hotkeyScope: InlineCellHotkeyScope.InlineCell,
}),
[activity.id],

View File

@ -1,3 +1,4 @@
import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObjectRecord';
import { IconCalendar } from '@/ui/display/icon/index';
import { FieldContext } from '@/ui/object/field/contexts/FieldContext';
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 { InlineCellHotkeyScope } from '@/ui/object/record-inline-cell/types/InlineCellHotkeyScope';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useUpdateActivityMutation } from '~/generated/graphql';
type ActivityEditorDateFieldProps = {
activityId: string;
@ -14,6 +14,30 @@ type ActivityEditorDateFieldProps = {
export const ActivityEditorDateField = ({
activityId,
}: 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 (
<RecoilScope>
<FieldContext.Provider
@ -29,7 +53,7 @@ export const ActivityEditorDateField = ({
fieldName: 'dueAt',
},
} satisfies FieldDefinition<FieldDateMetadata>,
useUpdateEntityMutation: useUpdateActivityMutation,
useUpdateEntityMutation: useUpdateOneObjectMutation,
hotkeyScope: InlineCellHotkeyScope.InlineCell,
}}
>

View File

@ -1,10 +1,12 @@
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 { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { RecordInlineCellContainer } from '@/ui/object/record-inline-cell/components/RecordInlineCellContainer';
import { FieldRecoilScopeContext } from '@/ui/object/record-inline-cell/states/recoil-scope-contexts/FieldRecoilScopeContext';
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';
@ -12,8 +14,8 @@ type ActivityRelationEditableFieldProps = {
activity?: Pick<Activity, 'id'> & {
activityTargets?: Array<
Pick<ActivityTarget, 'id' | 'personId' | 'companyId'> & {
person?: Pick<Person, 'id' | 'displayName'>;
company?: Pick<Company, 'id' | 'domainName' | 'name'>;
person?: Pick<Person, 'id' | 'firstName' | 'lastName'> | null;
company?: Pick<Company, 'id' | 'domainName' | 'name'> | null;
}
> | null;
};

View File

@ -2,12 +2,13 @@ import { useCallback, useMemo, useState } from 'react';
import styled from '@emotion/styled';
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 { useFilteredSearchCompanyQuery } from '@/companies/hooks/useFilteredSearchCompanyQuery';
import { useFilteredSearchPeopleQuery } from '@/people/hooks/useFilteredSearchPeopleQuery';
import { MultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
import { useInlineCell } from '@/ui/object/record-inline-cell/hooks/useInlineCell';
import { Activity, ActivityTarget } from '~/generated/graphql';
import { assertNotNull } from '~/utils/assert';
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 { GET_COMPANIES } from '@/companies/graphql/queries/getCompanies';
import { GET_PEOPLE } from '@/people/graphql/queries/getPeople';
import {
Activity,
ActivityTarget,
useAddActivityTargetsOnActivityMutation,
useRemoveActivityTargetsOnActivityMutation,
} from '~/generated/graphql';
import { Activity } from '@/activities/types/Activity';
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { useCreateOneObjectRecord } from '@/object-record/hooks/useCreateOneObjectRecord';
import { useDeleteOneObjectRecord } from '@/object-record/hooks/useDeleteOneObjectRecord';
import { GET_ACTIVITY } from '../graphql/queries/getActivity';
import { ActivityTargetableEntityType } from '../types/ActivityTargetableEntity';
import { ActivityTargetableEntityForSelect } from '../types/ActivityTargetableEntityForSelect';
export const useHandleCheckableActivityTargetChange = ({
@ -23,23 +16,12 @@ export const useHandleCheckableActivityTargetChange = ({
> | null;
};
}) => {
const [addActivityTargetsOnActivity] =
useAddActivityTargetsOnActivityMutation({
refetchQueries: [
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_ACTIVITY) ?? '',
],
});
const [removeActivityTargetsOnActivity] =
useRemoveActivityTargetsOnActivityMutation({
refetchQueries: [
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_ACTIVITY) ?? '',
],
});
const { createOneObject } = useCreateOneObjectRecord({
objectNamePlural: 'activityTargetV2',
});
const { deleteOneObject } = useDeleteOneObjectRecord({
objectNamePlural: 'activityTargetV2',
});
return async (
entityValues: Record<string, boolean>,
@ -59,24 +41,19 @@ export const useHandleCheckableActivityTargetChange = ({
({ id }) => entityValues[id] && !currentEntityIds.includes(id),
);
if (entitiesToAdd.length)
await addActivityTargetsOnActivity({
variables: {
if (entitiesToAdd.length) {
entitiesToAdd.map((entity) => {
createOneObject?.({
activityId: activity.id,
activityTargetInputs: entitiesToAdd.map((entity) => ({
activityTargetInputs: {
id: v4(),
createdAt: new Date().toISOString(),
companyId:
entity.entityType === ActivityTargetableEntityType.Company
? entity.id
: null,
personId:
entity.entityType === ActivityTargetableEntityType.Person
? entity.id
: null,
})),
},
companyId: entity.entityType === 'Company' ? entity.id : null,
personId: entity.entityType === 'Person' ? entity.id : null,
},
});
});
}
const activityTargetIdsToDelete = activity.activityTargets
? activity.activityTargets
@ -88,12 +65,10 @@ export const useHandleCheckableActivityTargetChange = ({
.map(({ id }) => id)
: [];
if (activityTargetIdsToDelete.length)
await removeActivityTargetsOnActivity({
variables: {
activityId: activity.id,
activityTargetIds: activityTargetIdsToDelete,
},
if (activityTargetIdsToDelete.length) {
activityTargetIdsToDelete.map((id) => {
deleteOneObject?.(id);
});
}
};
};

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
import { ReactElement } from 'react';
import styled from '@emotion/styled';
import { NoteForList } from '../../types/NoteForList';
import { Note } from '@/activities/types/Note';
import { NoteCard } from './NoteCard';
type NoteListProps = {
title: string;
notes: NoteForList[];
notes: Note[];
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';
export const useNotes = (entity: ActivityTargetableEntity) => {
const { data: notesData } = useGetActivitiesQuery({
variables: {
where: {
type: { equals: ActivityType.Note },
activityTargets: {
some: {
OR: [
{ companyId: { equals: entity.id } },
{ personId: { equals: entity.id } },
],
},
const { objects: notes } = useFindManyObjectRecords({
objectNamePlural: 'activitiesV2',
filter: {
type: { equals: 'None' },
activityTargets: {
some: {
OR: [
{ companyId: { equals: entity.id } },
{ personId: { equals: entity.id } },
],
},
},
},
});
const notes = notesData?.findManyActivities;
return {
notes,
notes: notes as Note[],
};
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,13 +2,17 @@ import { isNonEmptyArray } from '@apollo/client/utilities';
import styled from '@emotion/styled';
import CommentCounter from '@/activities/comment/CommentCounter';
import { Activity } from '@/activities/types/Activity';
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';
type TimelineActivityCardFooterProps = {
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 && (
<UserChip
id={activity.assignee.id}
name={activity.assignee.displayName ?? ''}
name={
activity.assignee.firstName +
' ' +
activity.assignee.lastName ?? ''
}
pictureUrl={activity.assignee.avatarUrl ?? ''}
/>
)}

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,9 +4,6 @@ import { Meta, StoryObj } from '@storybook/react';
import { fireEvent, within } from '@storybook/testing-library';
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 { GET_COMPANY } from '@/companies/graphql/queries/getCompany';
import { AppPath } from '@/types/AppPath';
@ -16,7 +13,6 @@ import {
PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedActivities, mockedTasks } from '~/testing/mock-data/activities';
import { mockedCompaniesData } from '~/testing/mock-data/companies';
import { CompanyShow } from '../CompanyShow';
@ -32,19 +28,6 @@ const meta: Meta<PageDecoratorArgs> = {
parameters: {
msw: [
...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) => {
return res(
ctx.data({
@ -90,23 +73,6 @@ export const EditNoteByAddButton: Story = {
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(
getOperationName(UPDATE_ONE_COMPANY) ?? '',
(req, res, ctx) => {
@ -145,23 +111,6 @@ export const NoteTab: Story = {
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(
getOperationName(UPDATE_ONE_COMPANY) ?? '',
(req, res, ctx) => {
@ -207,23 +156,6 @@ export const TaskTab: Story = {
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(
getOperationName(UPDATE_ONE_COMPANY) ?? '',
(req, res, ctx) => {

View File

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

View File

@ -1,8 +1,6 @@
import { getOperationName } from '@apollo/client/utilities';
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 { GET_CLIENT_CONFIG } from '@/client-config/graphql/queries/getClientConfig';
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_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
import {
ActivityType,
GetCompaniesQuery,
GetPeopleQuery,
GetPersonQuery,
@ -33,7 +30,7 @@ import {
} from '~/generated/graphql';
import { mockedApiKeys } from '~/testing/mock-data/api-keys';
import { mockedActivities, mockedTasks } from './mock-data/activities';
import { mockedActivities } from './mock-data/activities';
import {
mockedCompaniesData,
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) => {
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(
getOperationName(INSERT_ONE_COMPANY) ?? '',
(req, res, ctx) => {

View File

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