diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index 9c6451258..9ebf6e2aa 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -3372,57 +3372,6 @@ export type WorkspaceUpdateInput = { workspaceMember?: InputMaybe; }; -export type CreateEventMutationVariables = Exact<{ - type: Scalars['String']; - data: Scalars['JSON']; -}>; - - -export type CreateEventMutation = { __typename?: 'Mutation', createEvent: { __typename?: 'Analytics', success: boolean } }; - -export type CheckUserExistsQueryVariables = Exact<{ - email: Scalars['String']; -}>; - - -export type CheckUserExistsQuery = { __typename?: 'Query', checkUserExists: { __typename?: 'UserExists', exists: boolean } }; - -export type ChallengeMutationVariables = Exact<{ - email: Scalars['String']; - password: Scalars['String']; -}>; - - -export type ChallengeMutation = { __typename?: 'Mutation', challenge: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } }; - -export type SignUpMutationVariables = Exact<{ - email: Scalars['String']; - password: Scalars['String']; - workspaceInviteHash?: InputMaybe; -}>; - - -export type SignUpMutation = { __typename?: 'Mutation', signUp: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } }; - -export type VerifyMutationVariables = Exact<{ - loginToken: Scalars['String']; -}>; - - -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null } } | null }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; - -export type RenewTokenMutationVariables = Exact<{ - refreshToken: Scalars['String']; -}>; - - -export type RenewTokenMutation = { __typename?: 'Mutation', renewToken: { __typename?: 'AuthTokens', tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', expiresAt: string, token: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; - -export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; - - -export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', demoMode: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean } } }; - export type CreateCommentMutationVariables = Exact<{ commentId: Scalars['String']; commentText: Scalars['String']; @@ -3498,6 +3447,57 @@ export type UpdateCommentThreadMutationVariables = Exact<{ export type UpdateCommentThreadMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, body?: string | null, title?: string | null, type: ActivityType } }; +export type CreateEventMutationVariables = Exact<{ + type: Scalars['String']; + data: Scalars['JSON']; +}>; + + +export type CreateEventMutation = { __typename?: 'Mutation', createEvent: { __typename?: 'Analytics', success: boolean } }; + +export type CheckUserExistsQueryVariables = Exact<{ + email: Scalars['String']; +}>; + + +export type CheckUserExistsQuery = { __typename?: 'Query', checkUserExists: { __typename?: 'UserExists', exists: boolean } }; + +export type ChallengeMutationVariables = Exact<{ + email: Scalars['String']; + password: Scalars['String']; +}>; + + +export type ChallengeMutation = { __typename?: 'Mutation', challenge: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } }; + +export type SignUpMutationVariables = Exact<{ + email: Scalars['String']; + password: Scalars['String']; + workspaceInviteHash?: InputMaybe; +}>; + + +export type SignUpMutation = { __typename?: 'Mutation', signUp: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } }; + +export type VerifyMutationVariables = Exact<{ + loginToken: Scalars['String']; +}>; + + +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null } } | null }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; + +export type RenewTokenMutationVariables = Exact<{ + refreshToken: Scalars['String']; +}>; + + +export type RenewTokenMutation = { __typename?: 'Mutation', renewToken: { __typename?: 'AuthTokens', tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', expiresAt: string, token: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; + +export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', demoMode: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean } } }; + export type GetCompaniesQueryVariables = Exact<{ orderBy?: InputMaybe | CompanyOrderByWithRelationInput>; where?: InputMaybe; @@ -3649,14 +3649,15 @@ export type GetPipelinesQueryVariables = Exact<{ }>; -export type GetPipelinesQuery = { __typename?: 'Query', findManyPipeline: Array<{ __typename?: 'Pipeline', id: string, name: string, pipelineProgressableType: PipelineProgressableType, pipelineStages?: Array<{ __typename?: 'PipelineStage', id: string, name: string, color: string, index?: number | null, pipelineProgresses?: Array<{ __typename?: 'PipelineProgress', id: string }> | null }> | null }> }; +export type GetPipelinesQuery = { __typename?: 'Query', findManyPipeline: Array<{ __typename?: 'Pipeline', id: string, name: string, pipelineProgressableType: PipelineProgressableType, pipelineStages?: Array<{ __typename?: 'PipelineStage', id: string, name: string, color: string, index?: number | null }> | null }> }; export type GetPipelineProgressQueryVariables = Exact<{ where?: InputMaybe; + orderBy?: InputMaybe | PipelineProgressOrderByWithRelationInput>; }>; -export type GetPipelineProgressQuery = { __typename?: 'Query', findManyPipelineProgress: Array<{ __typename?: 'PipelineProgress', id: string, progressableType: PipelineProgressableType, progressableId: string, amount?: number | null, closeDate?: string | null }> }; +export type GetPipelineProgressQuery = { __typename?: 'Query', findManyPipelineProgress: Array<{ __typename?: 'PipelineProgress', id: string, pipelineStageId: string, progressableType: PipelineProgressableType, progressableId: string, amount?: number | null, closeDate?: string | null }> }; export type UpdateOnePipelineProgressMutationVariables = Exact<{ id?: InputMaybe; @@ -3797,297 +3798,6 @@ export type RemoveWorkspaceMemberMutationVariables = Exact<{ export type RemoveWorkspaceMemberMutation = { __typename?: 'Mutation', deleteWorkspaceMember: { __typename?: 'WorkspaceMember', id: string } }; -export const CreateEventDocument = gql` - mutation CreateEvent($type: String!, $data: JSON!) { - createEvent(type: $type, data: $data) { - success - } -} - `; -export type CreateEventMutationFn = Apollo.MutationFunction; - -/** - * __useCreateEventMutation__ - * - * To run a mutation, you first call `useCreateEventMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useCreateEventMutation` 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 [createEventMutation, { data, loading, error }] = useCreateEventMutation({ - * variables: { - * type: // value for 'type' - * data: // value for 'data' - * }, - * }); - */ -export function useCreateEventMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(CreateEventDocument, options); - } -export type CreateEventMutationHookResult = ReturnType; -export type CreateEventMutationResult = Apollo.MutationResult; -export type CreateEventMutationOptions = Apollo.BaseMutationOptions; -export const CheckUserExistsDocument = gql` - query CheckUserExists($email: String!) { - checkUserExists(email: $email) { - exists - } -} - `; - -/** - * __useCheckUserExistsQuery__ - * - * To run a query within a React component, call `useCheckUserExistsQuery` and pass it any options that fit your needs. - * When your component renders, `useCheckUserExistsQuery` 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 } = useCheckUserExistsQuery({ - * variables: { - * email: // value for 'email' - * }, - * }); - */ -export function useCheckUserExistsQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(CheckUserExistsDocument, options); - } -export function useCheckUserExistsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(CheckUserExistsDocument, options); - } -export type CheckUserExistsQueryHookResult = ReturnType; -export type CheckUserExistsLazyQueryHookResult = ReturnType; -export type CheckUserExistsQueryResult = Apollo.QueryResult; -export const ChallengeDocument = gql` - mutation Challenge($email: String!, $password: String!) { - challenge(email: $email, password: $password) { - loginToken { - expiresAt - token - } - } -} - `; -export type ChallengeMutationFn = Apollo.MutationFunction; - -/** - * __useChallengeMutation__ - * - * To run a mutation, you first call `useChallengeMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useChallengeMutation` 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 [challengeMutation, { data, loading, error }] = useChallengeMutation({ - * variables: { - * email: // value for 'email' - * password: // value for 'password' - * }, - * }); - */ -export function useChallengeMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(ChallengeDocument, options); - } -export type ChallengeMutationHookResult = ReturnType; -export type ChallengeMutationResult = Apollo.MutationResult; -export type ChallengeMutationOptions = Apollo.BaseMutationOptions; -export const SignUpDocument = gql` - mutation SignUp($email: String!, $password: String!, $workspaceInviteHash: String) { - signUp( - email: $email - password: $password - workspaceInviteHash: $workspaceInviteHash - ) { - loginToken { - expiresAt - token - } - } -} - `; -export type SignUpMutationFn = Apollo.MutationFunction; - -/** - * __useSignUpMutation__ - * - * To run a mutation, you first call `useSignUpMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useSignUpMutation` 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 [signUpMutation, { data, loading, error }] = useSignUpMutation({ - * variables: { - * email: // value for 'email' - * password: // value for 'password' - * workspaceInviteHash: // value for 'workspaceInviteHash' - * }, - * }); - */ -export function useSignUpMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(SignUpDocument, options); - } -export type SignUpMutationHookResult = ReturnType; -export type SignUpMutationResult = Apollo.MutationResult; -export type SignUpMutationOptions = Apollo.BaseMutationOptions; -export const VerifyDocument = gql` - mutation Verify($loginToken: String!) { - verify(loginToken: $loginToken) { - user { - id - email - displayName - firstName - lastName - workspaceMember { - id - workspace { - id - domainName - displayName - logo - } - } - } - tokens { - accessToken { - token - expiresAt - } - refreshToken { - token - expiresAt - } - } - } -} - `; -export type VerifyMutationFn = Apollo.MutationFunction; - -/** - * __useVerifyMutation__ - * - * To run a mutation, you first call `useVerifyMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useVerifyMutation` 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 [verifyMutation, { data, loading, error }] = useVerifyMutation({ - * variables: { - * loginToken: // value for 'loginToken' - * }, - * }); - */ -export function useVerifyMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(VerifyDocument, options); - } -export type VerifyMutationHookResult = ReturnType; -export type VerifyMutationResult = Apollo.MutationResult; -export type VerifyMutationOptions = Apollo.BaseMutationOptions; -export const RenewTokenDocument = gql` - mutation RenewToken($refreshToken: String!) { - renewToken(refreshToken: $refreshToken) { - tokens { - accessToken { - expiresAt - token - } - refreshToken { - token - expiresAt - } - } - } -} - `; -export type RenewTokenMutationFn = Apollo.MutationFunction; - -/** - * __useRenewTokenMutation__ - * - * To run a mutation, you first call `useRenewTokenMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useRenewTokenMutation` 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 [renewTokenMutation, { data, loading, error }] = useRenewTokenMutation({ - * variables: { - * refreshToken: // value for 'refreshToken' - * }, - * }); - */ -export function useRenewTokenMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(RenewTokenDocument, options); - } -export type RenewTokenMutationHookResult = ReturnType; -export type RenewTokenMutationResult = Apollo.MutationResult; -export type RenewTokenMutationOptions = Apollo.BaseMutationOptions; -export const GetClientConfigDocument = gql` - query GetClientConfig { - clientConfig { - authProviders { - google - password - } - demoMode - debugMode - telemetry { - enabled - anonymizationEnabled - } - } -} - `; - -/** - * __useGetClientConfigQuery__ - * - * To run a query within a React component, call `useGetClientConfigQuery` and pass it any options that fit your needs. - * When your component renders, `useGetClientConfigQuery` 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 } = useGetClientConfigQuery({ - * variables: { - * }, - * }); - */ -export function useGetClientConfigQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetClientConfigDocument, options); - } -export function useGetClientConfigLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetClientConfigDocument, options); - } -export type GetClientConfigQueryHookResult = ReturnType; -export type GetClientConfigLazyQueryHookResult = ReturnType; -export type GetClientConfigQueryResult = Apollo.QueryResult; export const CreateCommentDocument = gql` mutation CreateComment($commentId: String!, $commentText: String!, $authorId: String!, $commentThreadId: String!, $createdAt: DateTime!) { createOneComment( @@ -4497,6 +4207,297 @@ export function useUpdateCommentThreadMutation(baseOptions?: Apollo.MutationHook export type UpdateCommentThreadMutationHookResult = ReturnType; export type UpdateCommentThreadMutationResult = Apollo.MutationResult; export type UpdateCommentThreadMutationOptions = Apollo.BaseMutationOptions; +export const CreateEventDocument = gql` + mutation CreateEvent($type: String!, $data: JSON!) { + createEvent(type: $type, data: $data) { + success + } +} + `; +export type CreateEventMutationFn = Apollo.MutationFunction; + +/** + * __useCreateEventMutation__ + * + * To run a mutation, you first call `useCreateEventMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateEventMutation` 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 [createEventMutation, { data, loading, error }] = useCreateEventMutation({ + * variables: { + * type: // value for 'type' + * data: // value for 'data' + * }, + * }); + */ +export function useCreateEventMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreateEventDocument, options); + } +export type CreateEventMutationHookResult = ReturnType; +export type CreateEventMutationResult = Apollo.MutationResult; +export type CreateEventMutationOptions = Apollo.BaseMutationOptions; +export const CheckUserExistsDocument = gql` + query CheckUserExists($email: String!) { + checkUserExists(email: $email) { + exists + } +} + `; + +/** + * __useCheckUserExistsQuery__ + * + * To run a query within a React component, call `useCheckUserExistsQuery` and pass it any options that fit your needs. + * When your component renders, `useCheckUserExistsQuery` 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 } = useCheckUserExistsQuery({ + * variables: { + * email: // value for 'email' + * }, + * }); + */ +export function useCheckUserExistsQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(CheckUserExistsDocument, options); + } +export function useCheckUserExistsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(CheckUserExistsDocument, options); + } +export type CheckUserExistsQueryHookResult = ReturnType; +export type CheckUserExistsLazyQueryHookResult = ReturnType; +export type CheckUserExistsQueryResult = Apollo.QueryResult; +export const ChallengeDocument = gql` + mutation Challenge($email: String!, $password: String!) { + challenge(email: $email, password: $password) { + loginToken { + expiresAt + token + } + } +} + `; +export type ChallengeMutationFn = Apollo.MutationFunction; + +/** + * __useChallengeMutation__ + * + * To run a mutation, you first call `useChallengeMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useChallengeMutation` 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 [challengeMutation, { data, loading, error }] = useChallengeMutation({ + * variables: { + * email: // value for 'email' + * password: // value for 'password' + * }, + * }); + */ +export function useChallengeMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(ChallengeDocument, options); + } +export type ChallengeMutationHookResult = ReturnType; +export type ChallengeMutationResult = Apollo.MutationResult; +export type ChallengeMutationOptions = Apollo.BaseMutationOptions; +export const SignUpDocument = gql` + mutation SignUp($email: String!, $password: String!, $workspaceInviteHash: String) { + signUp( + email: $email + password: $password + workspaceInviteHash: $workspaceInviteHash + ) { + loginToken { + expiresAt + token + } + } +} + `; +export type SignUpMutationFn = Apollo.MutationFunction; + +/** + * __useSignUpMutation__ + * + * To run a mutation, you first call `useSignUpMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useSignUpMutation` 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 [signUpMutation, { data, loading, error }] = useSignUpMutation({ + * variables: { + * email: // value for 'email' + * password: // value for 'password' + * workspaceInviteHash: // value for 'workspaceInviteHash' + * }, + * }); + */ +export function useSignUpMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(SignUpDocument, options); + } +export type SignUpMutationHookResult = ReturnType; +export type SignUpMutationResult = Apollo.MutationResult; +export type SignUpMutationOptions = Apollo.BaseMutationOptions; +export const VerifyDocument = gql` + mutation Verify($loginToken: String!) { + verify(loginToken: $loginToken) { + user { + id + email + displayName + firstName + lastName + workspaceMember { + id + workspace { + id + domainName + displayName + logo + } + } + } + tokens { + accessToken { + token + expiresAt + } + refreshToken { + token + expiresAt + } + } + } +} + `; +export type VerifyMutationFn = Apollo.MutationFunction; + +/** + * __useVerifyMutation__ + * + * To run a mutation, you first call `useVerifyMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useVerifyMutation` 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 [verifyMutation, { data, loading, error }] = useVerifyMutation({ + * variables: { + * loginToken: // value for 'loginToken' + * }, + * }); + */ +export function useVerifyMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(VerifyDocument, options); + } +export type VerifyMutationHookResult = ReturnType; +export type VerifyMutationResult = Apollo.MutationResult; +export type VerifyMutationOptions = Apollo.BaseMutationOptions; +export const RenewTokenDocument = gql` + mutation RenewToken($refreshToken: String!) { + renewToken(refreshToken: $refreshToken) { + tokens { + accessToken { + expiresAt + token + } + refreshToken { + token + expiresAt + } + } + } +} + `; +export type RenewTokenMutationFn = Apollo.MutationFunction; + +/** + * __useRenewTokenMutation__ + * + * To run a mutation, you first call `useRenewTokenMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useRenewTokenMutation` 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 [renewTokenMutation, { data, loading, error }] = useRenewTokenMutation({ + * variables: { + * refreshToken: // value for 'refreshToken' + * }, + * }); + */ +export function useRenewTokenMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(RenewTokenDocument, options); + } +export type RenewTokenMutationHookResult = ReturnType; +export type RenewTokenMutationResult = Apollo.MutationResult; +export type RenewTokenMutationOptions = Apollo.BaseMutationOptions; +export const GetClientConfigDocument = gql` + query GetClientConfig { + clientConfig { + authProviders { + google + password + } + demoMode + debugMode + telemetry { + enabled + anonymizationEnabled + } + } +} + `; + +/** + * __useGetClientConfigQuery__ + * + * To run a query within a React component, call `useGetClientConfigQuery` and pass it any options that fit your needs. + * When your component renders, `useGetClientConfigQuery` 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 } = useGetClientConfigQuery({ + * variables: { + * }, + * }); + */ +export function useGetClientConfigQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetClientConfigDocument, options); + } +export function useGetClientConfigLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetClientConfigDocument, options); + } +export type GetClientConfigQueryHookResult = ReturnType; +export type GetClientConfigLazyQueryHookResult = ReturnType; +export type GetClientConfigQueryResult = Apollo.QueryResult; export const GetCompaniesDocument = gql` query GetCompanies($orderBy: [CompanyOrderByWithRelationInput!], $where: CompanyWhereInput) { companies: findManyCompany(orderBy: $orderBy, where: $where) { @@ -5227,9 +5228,6 @@ export const GetPipelinesDocument = gql` name color index - pipelineProgresses { - id - } } } } @@ -5263,9 +5261,10 @@ export type GetPipelinesQueryHookResult = ReturnType; export type GetPipelinesQueryResult = Apollo.QueryResult; export const GetPipelineProgressDocument = gql` - query GetPipelineProgress($where: PipelineProgressWhereInput) { - findManyPipelineProgress(where: $where, orderBy: {createdAt: asc}) { + query GetPipelineProgress($where: PipelineProgressWhereInput, $orderBy: [PipelineProgressOrderByWithRelationInput!]) { + findManyPipelineProgress(where: $where, orderBy: $orderBy) { id + pipelineStageId progressableType progressableId amount @@ -5287,6 +5286,7 @@ export const GetPipelineProgressDocument = gql` * const { data, loading, error } = useGetPipelineProgressQuery({ * variables: { * where: // value for 'where' + * orderBy: // value for 'orderBy' * }, * }); */ diff --git a/front/src/modules/companies/__stories__/Board.stories.tsx b/front/src/modules/companies/__stories__/Board.stories.tsx index 59de69c84..bb2e68406 100644 --- a/front/src/modules/companies/__stories__/Board.stories.tsx +++ b/front/src/modules/companies/__stories__/Board.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react'; -import { companyBoardOptions } from '@/companies/components/companyBoardOptions'; import { EntityBoard } from '@/pipeline/components/EntityBoard'; +import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions'; import { BoardDecorator } from '~/testing/decorators'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; @@ -17,7 +17,12 @@ type Story = StoryObj; export const OneColumnBoard: Story = { render: getRenderWrapperForComponent( - , + { + return; + }} + />, ), parameters: { msw: graphqlMocks, diff --git a/front/src/modules/companies/__stories__/mock-data.ts b/front/src/modules/companies/__stories__/mock-data.ts index 748e9e58a..f5cbb6204 100644 --- a/front/src/modules/companies/__stories__/mock-data.ts +++ b/front/src/modules/companies/__stories__/mock-data.ts @@ -9,10 +9,6 @@ export const pipeline = { name: 'New', index: 0, color: '#B76796', - pipelineProgresses: [ - { id: 'fe256b39-3ec3-4fe7-8998-b76aa0bfb600' }, - { id: '4a886c90-f4f2-4984-8222-882ebbb905d6' }, - ], }, { id: 'pipeline-stage-2', diff --git a/front/src/modules/companies/components/CompanyBoardCard.tsx b/front/src/modules/companies/components/CompanyBoardCard.tsx index 2aa42c334..4ab220cc3 100644 --- a/front/src/modules/companies/components/CompanyBoardCard.tsx +++ b/front/src/modules/companies/components/CompanyBoardCard.tsx @@ -5,7 +5,7 @@ import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; import { companyProgressesFamilyState } from '@/companies/states/companyProgressesFamilyState'; -import { GET_PIPELINES } from '@/pipeline/queries'; +import { GET_PIPELINE_PROGRESS, GET_PIPELINES } from '@/pipeline/queries'; import { BoardCardContext } from '@/pipeline/states/BoardCardContext'; import { pipelineProgressIdScopedState } from '@/pipeline/states/pipelineProgressIdScopedState'; import { selectedBoardCardsState } from '@/pipeline/states/selectedBoardCardsState'; @@ -108,7 +108,10 @@ export function CompanyBoardCard() { amount: pipelineProgress.amount, closeDate: pipelineProgress.closeDate || null, }, - refetchQueries: [getOperationName(GET_PIPELINES) ?? ''], + refetchQueries: [ + getOperationName(GET_PIPELINE_PROGRESS) ?? '', + getOperationName(GET_PIPELINES) ?? '', + ], }); }, [updatePipelineProgress], diff --git a/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx b/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx index b1c0361d6..661fb16cf 100644 --- a/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx +++ b/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx @@ -1,21 +1,26 @@ +import { Context } from 'react'; + import { FilterDropdownEntitySearchSelect } from '@/ui/filter-n-sort/components/FilterDropdownEntitySearchSelect'; import { filterDropdownSearchInputScopedState } from '@/ui/filter-n-sort/states/filterDropdownSearchInputScopedState'; import { filterDropdownSelectedEntityIdScopedState } from '@/ui/filter-n-sort/states/filterDropdownSelectedEntityIdScopedState'; import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedValue } from '@/ui/recoil-scope/hooks/useRecoilScopedValue'; -import { TableContext } from '@/ui/table/states/TableContext'; import { useFilteredSearchCompanyQuery } from '../queries'; -export function FilterDropdownCompanySearchSelect() { +export function FilterDropdownCompanySearchSelect({ + context, +}: { + context: Context; +}) { const filterDropdownSearchInput = useRecoilScopedValue( filterDropdownSearchInputScopedState, - TableContext, + context, ); const [filterDropdownSelectedEntityId] = useRecoilScopedState( filterDropdownSelectedEntityIdScopedState, - TableContext, + context, ); const usersForSelect = useFilteredSearchCompanyQuery({ @@ -28,7 +33,7 @@ export function FilterDropdownCompanySearchSelect() { return ( ); } diff --git a/front/src/modules/companies/components/HookCompanyBoard.tsx b/front/src/modules/companies/components/HooksCompanyBoard.tsx similarity index 64% rename from front/src/modules/companies/components/HookCompanyBoard.tsx rename to front/src/modules/companies/components/HooksCompanyBoard.tsx index 8f8d3da27..9a9dca61b 100644 --- a/front/src/modules/companies/components/HookCompanyBoard.tsx +++ b/front/src/modules/companies/components/HooksCompanyBoard.tsx @@ -1,6 +1,7 @@ -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import { useRecoilCallback, useRecoilState } from 'recoil'; +import { useInitializeCompanyBoardFilters } from '@/companies/hooks/useInitializeCompanyBoardFilters'; import { companyProgressesFamilyState } from '@/companies/states/companyProgressesFamilyState'; import { CompanyForBoard, @@ -11,15 +12,30 @@ import { boardState } from '@/pipeline/states/boardState'; import { currentPipelineState } from '@/pipeline/states/currentPipelineState'; import { isBoardLoadedState } from '@/pipeline/states/isBoardLoadedState'; import { BoardPipelineStageColumn } from '@/ui/board/components/Board'; +import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState'; +import { FilterDefinition } from '@/ui/filter-n-sort/types/FilterDefinition'; +import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause'; +import { useRecoilScopedValue } from '@/ui/recoil-scope/hooks/useRecoilScopedValue'; +import { PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By } from '~/generated/graphql'; import { Pipeline, - PipelineStage, useGetCompaniesQuery, useGetPipelineProgressQuery, useGetPipelinesQuery, } from '~/generated/graphql'; -export function HookCompanyBoard() { +import { CompanyBoardContext } from '../states/CompanyBoardContext'; + +export function HooksCompanyBoard({ + availableFilters, + orderBy, +}: { + availableFilters: FilterDefinition[]; + orderBy: PipelineProgresses_Order_By[]; +}) { + useInitializeCompanyBoardFilters({ + availableFilters, + }); const [currentPipeline, setCurrentPipeline] = useRecoilState(currentPipelineState); @@ -44,29 +60,47 @@ export function HookCompanyBoard() { title: pipelineStage.name, colorCode: pipelineStage.color, index: pipelineStage.index || 0, - pipelineProgressIds: - pipelineStage.pipelineProgresses?.map( - (item) => item.id as string, - ) || [], + pipelineProgressIds: [], })) || []; setBoard(initialBoard); - setIsBoardLoaded(true); }, }); - const pipelineProgressIds = currentPipeline?.pipelineStages - ?.map((pipelineStage: PipelineStage) => - ( - pipelineStage.pipelineProgresses?.map((item) => item.id as string) || [] - ).flat(), - ) + const pipelineStageIds = currentPipeline?.pipelineStages + ?.map((pipelineStage) => pipelineStage.id) .flat(); + const filters = useRecoilScopedValue(filtersScopedState, CompanyBoardContext); + + const whereFilters = useMemo(() => { + return { + AND: [ + { pipelineStageId: { in: pipelineStageIds } }, + ...filters.map(turnFilterIntoWhereClause), + ], + }; + }, [filters, pipelineStageIds]) as any; + const pipelineProgressesQuery = useGetPipelineProgressQuery({ variables: { - where: { - id: { in: pipelineProgressIds }, - }, + where: whereFilters, + orderBy, + }, + onCompleted: (data) => { + const pipelineProgresses = data?.findManyPipelineProgress || []; + setBoard((board) => + board?.map((boardPipelineStage) => ({ + ...boardPipelineStage, + pipelineProgressIds: pipelineProgresses + .filter( + (pipelineProgress) => + pipelineProgress.pipelineStageId === + boardPipelineStage.pipelineStageId, + ) + .map((pipelineProgress) => pipelineProgress.id), + })), + ); + setIsBoardLoaded(true); }, }); diff --git a/front/src/modules/companies/components/NewCompanyProgressButton.tsx b/front/src/modules/companies/components/NewCompanyProgressButton.tsx index 65f74f9be..7b974960b 100644 --- a/front/src/modules/companies/components/NewCompanyProgressButton.tsx +++ b/front/src/modules/companies/components/NewCompanyProgressButton.tsx @@ -3,7 +3,7 @@ import { getOperationName } from '@apollo/client/utilities'; import { useRecoilState } from 'recoil'; import { v4 as uuidv4 } from 'uuid'; -import { GET_PIPELINES } from '@/pipeline/queries'; +import { GET_PIPELINE_PROGRESS, GET_PIPELINES } from '@/pipeline/queries'; import { BoardColumnContext } from '@/pipeline/states/BoardColumnContext'; import { boardState } from '@/pipeline/states/boardState'; import { currentPipelineState } from '@/pipeline/states/currentPipelineState'; @@ -37,7 +37,10 @@ export function NewCompanyProgressButton() { } = usePreviousHotkeyScope(); const [createOnePipelineProgress] = useCreateOnePipelineProgressMutation({ - refetchQueries: [getOperationName(GET_PIPELINES) ?? ''], + refetchQueries: [ + getOperationName(GET_PIPELINE_PROGRESS) ?? '', + getOperationName(GET_PIPELINES) ?? '', + ], }); const handleEntitySelect = useCallback( diff --git a/front/src/modules/companies/hooks/useInitializeCompanyBoardFilters.ts b/front/src/modules/companies/hooks/useInitializeCompanyBoardFilters.ts new file mode 100644 index 000000000..8660b01a3 --- /dev/null +++ b/front/src/modules/companies/hooks/useInitializeCompanyBoardFilters.ts @@ -0,0 +1,21 @@ +import { useEffect } from 'react'; + +import { CompanyBoardContext } from '@/companies/states/CompanyBoardContext'; +import { availableFiltersScopedState } from '@/ui/filter-n-sort/states/availableFiltersScopedState'; +import { FilterDefinition } from '@/ui/filter-n-sort/types/FilterDefinition'; +import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState'; + +export function useInitializeCompanyBoardFilters({ + availableFilters, +}: { + availableFilters: FilterDefinition[]; +}) { + const [, setAvailableFilters] = useRecoilScopedState( + availableFiltersScopedState, + CompanyBoardContext, + ); + + useEffect(() => { + setAvailableFilters(availableFilters); + }, [setAvailableFilters, availableFilters]); +} diff --git a/front/src/modules/pipeline/components/EntityBoard.tsx b/front/src/modules/pipeline/components/EntityBoard.tsx index 56e672f4e..cc00ed90a 100644 --- a/front/src/modules/pipeline/components/EntityBoard.tsx +++ b/front/src/modules/pipeline/components/EntityBoard.tsx @@ -1,10 +1,18 @@ import { useCallback } from 'react'; +import { getOperationName } from '@apollo/client/utilities'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; import { DragDropContext, OnDragEndResponder } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350 +import { IconList } from '@tabler/icons-react'; import { useRecoilState } from 'recoil'; +import { CompanyBoardContext } from '@/companies/states/CompanyBoardContext'; +import { BoardHeader } from '@/ui/board/components/BoardHeader'; +import { SelectedSortType } from '@/ui/filter-n-sort/types/interface'; import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope'; import { PipelineProgress, + PipelineProgressOrderByWithRelationInput, PipelineStage, useUpdateOnePipelineProgressStageMutation, } from '~/generated/graphql'; @@ -13,14 +21,31 @@ import { getOptimisticlyUpdatedBoard, StyledBoard, } from '../../ui/board/components/Board'; +import { GET_PIPELINE_PROGRESS } from '../queries'; import { BoardColumnContext } from '../states/BoardColumnContext'; import { boardState } from '../states/boardState'; import { BoardOptions } from '../types/BoardOptions'; import { EntityBoardColumn } from './EntityBoardColumn'; -export function EntityBoard({ boardOptions }: { boardOptions: BoardOptions }) { +const StyledBoardWithHeader = styled.div` + display: flex; + flex: 1; + flex-direction: column; + width: 100%; +`; + +export function EntityBoard({ + boardOptions, + updateSorts, +}: { + boardOptions: BoardOptions; + updateSorts: ( + sorts: Array>, + ) => void; +}) { const [board, setBoard] = useRecoilState(boardState); + const theme = useTheme(); const [updatePipelineProgressStage] = useUpdateOnePipelineProgressStageMutation(); @@ -34,6 +59,7 @@ export function EntityBoard({ boardOptions }: { boardOptions: BoardOptions }) { id: pipelineProgressId, pipelineStageId, }, + refetchQueries: [getOperationName(GET_PIPELINE_PROGRESS) ?? ''], }); }, [updatePipelineProgressStage], @@ -69,18 +95,27 @@ export function EntityBoard({ boardOptions }: { boardOptions: BoardOptions }) { : []; return (board?.length ?? 0) > 0 ? ( - - - {sortedBoard.map((column) => ( - - - - ))} - - + + } + availableSorts={boardOptions.sorts} + onSortsUpdate={updateSorts} + context={CompanyBoardContext} + /> + + + {sortedBoard.map((column) => ( + + + + ))} + + + ) : ( <> ); diff --git a/front/src/modules/pipeline/queries/select.ts b/front/src/modules/pipeline/queries/select.ts index 4dea0a03b..5d64c1a38 100644 --- a/front/src/modules/pipeline/queries/select.ts +++ b/front/src/modules/pipeline/queries/select.ts @@ -1,5 +1,14 @@ import { gql } from '@apollo/client'; +import { SelectedSortType } from '@/ui/filter-n-sort/types/interface'; +import { + PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By, + SortOrder as Order_By, +} from '~/generated/graphql'; + +export type PipelineProgressesSelectedSortType = + SelectedSortType; + export const GET_PIPELINES = gql` query GetPipelines($where: PipelineWhereInput) { findManyPipeline(where: $where) { @@ -11,18 +20,19 @@ export const GET_PIPELINES = gql` name color index - pipelineProgresses { - id - } } } } `; export const GET_PIPELINE_PROGRESS = gql` - query GetPipelineProgress($where: PipelineProgressWhereInput) { - findManyPipelineProgress(where: $where, orderBy: { createdAt: asc }) { + query GetPipelineProgress( + $where: PipelineProgressWhereInput + $orderBy: [PipelineProgressOrderByWithRelationInput!] + ) { + findManyPipelineProgress(where: $where, orderBy: $orderBy) { id + pipelineStageId progressableType progressableId amount @@ -83,3 +93,9 @@ export const ADD_ENTITY_TO_PIPELINE = gql` } } `; + +export const defaultPipelineProgressOrderBy: PipelineProgresses_Order_By[] = [ + { + createdAt: Order_By.Asc, + }, +]; diff --git a/front/src/modules/pipeline/types/BoardOptions.ts b/front/src/modules/pipeline/types/BoardOptions.ts index 8f0a97874..fb273335e 100644 --- a/front/src/modules/pipeline/types/BoardOptions.ts +++ b/front/src/modules/pipeline/types/BoardOptions.ts @@ -1,4 +1,11 @@ +import { FilterDefinitionByEntity } from '@/ui/filter-n-sort/types/FilterDefinitionByEntity'; +import { SortType } from '@/ui/filter-n-sort/types/interface'; +import { PipelineProgress } from '~/generated/graphql'; +import { PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By } from '~/generated/graphql'; + export type BoardOptions = { newCardComponent: React.ReactNode; cardComponent: React.ReactNode; + filters: FilterDefinitionByEntity[]; + sorts: Array>; }; diff --git a/front/src/modules/ui/board/components/BoardHeader.tsx b/front/src/modules/ui/board/components/BoardHeader.tsx new file mode 100644 index 000000000..9d7aae2e7 --- /dev/null +++ b/front/src/modules/ui/board/components/BoardHeader.tsx @@ -0,0 +1,131 @@ +import { Context, ReactNode, useCallback, useState } from 'react'; +import styled from '@emotion/styled'; + +import { FilterDropdownButton } from '@/ui/filter-n-sort/components/FilterDropdownButton'; +import SortAndFilterBar from '@/ui/filter-n-sort/components/SortAndFilterBar'; +import { SortDropdownButton } from '@/ui/filter-n-sort/components/SortDropdownButton'; +import { FiltersHotkeyScope } from '@/ui/filter-n-sort/types/FiltersHotkeyScope'; +import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface'; + +type OwnProps = { + viewName: string; + viewIcon?: ReactNode; + availableSorts?: Array>; + onSortsUpdate?: (sorts: Array>) => void; + context: Context; +}; + +const StyledContainer = styled.div` + display: flex; + flex-direction: column; +`; + +const StyledTableHeader = styled.div` + align-items: center; + color: ${({ theme }) => theme.font.color.secondary}; + display: flex; + flex-direction: row; + font-weight: ${({ theme }) => theme.font.weight.medium}; + height: 40px; + justify-content: space-between; + padding-left: ${({ theme }) => theme.spacing(3)}; + padding-right: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledIcon = styled.div` + display: flex; + margin-left: ${({ theme }) => theme.spacing(1)}; + margin-right: ${({ theme }) => theme.spacing(2)}; + + & > svg { + font-size: ${({ theme }) => theme.icon.size.sm}; + } +`; + +const StyledViewSection = styled.div` + display: flex; +`; + +const StyledFilters = styled.div` + display: flex; + font-weight: ${({ theme }) => theme.font.weight.regular}; + gap: 2px; +`; + +export function BoardHeader({ + viewName, + viewIcon, + availableSorts, + onSortsUpdate, + context, +}: OwnProps) { + const [sorts, innerSetSorts] = useState>>( + [], + ); + + const sortSelect = useCallback( + (newSort: SelectedSortType) => { + const newSorts = updateSortOrFilterByKey(sorts, newSort); + innerSetSorts(newSorts); + onSortsUpdate && onSortsUpdate(newSorts); + }, + [onSortsUpdate, sorts], + ); + + const sortUnselect = useCallback( + (sortKey: string) => { + const newSorts = sorts.filter((sort) => sort.key !== sortKey); + innerSetSorts(newSorts); + onSortsUpdate && onSortsUpdate(newSorts); + }, + [onSortsUpdate, sorts], + ); + + return ( + + + + {viewIcon} + {viewName} + + + + + isSortSelected={sorts.length > 0} + availableSorts={availableSorts || []} + onSortSelect={sortSelect} + HotkeyScope={FiltersHotkeyScope.FilterDropdownButton} + /> + + + { + innerSetSorts([]); + onSortsUpdate && onSortsUpdate([]); + }} + /> + + ); +} + +function updateSortOrFilterByKey( + sorts: Readonly, + newSort: SortOrFilter, +): SortOrFilter[] { + const newSorts = [...sorts]; + const existingSortIndex = sorts.findIndex((sort) => sort.key === newSort.key); + + if (existingSortIndex !== -1) { + newSorts[existingSortIndex] = newSort; + } else { + newSorts.push(newSort); + } + + return newSorts; +} diff --git a/front/src/pages/opportunities/Opportunities.tsx b/front/src/pages/opportunities/Opportunities.tsx index b5fe95ec3..c04012ba5 100644 --- a/front/src/pages/opportunities/Opportunities.tsx +++ b/front/src/pages/opportunities/Opportunities.tsx @@ -1,26 +1,54 @@ +import { useCallback, useState } from 'react'; import { useTheme } from '@emotion/react'; -import { companyBoardOptions } from '@/companies/components/companyBoardOptions'; -import { HookCompanyBoard } from '@/companies/components/HookCompanyBoard'; +import { HooksCompanyBoard } from '@/companies/components/HooksCompanyBoard'; import { CompanyBoardContext } from '@/companies/states/CompanyBoardContext'; import { BoardActionBarButtonDeletePipelineProgress } from '@/pipeline/components/BoardActionBarButtonDeletePipelineProgress'; import { EntityBoard } from '@/pipeline/components/EntityBoard'; import { EntityBoardActionBar } from '@/pipeline/components/EntityBoardActionBar'; +import { + defaultPipelineProgressOrderBy, + PipelineProgressesSelectedSortType, +} from '@/pipeline/queries'; +import { reduceSortsToOrderBy } from '@/ui/filter-n-sort/helpers'; import { IconTargetArrow } from '@/ui/icon/index'; import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer'; import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope'; +import { PipelineProgressOrderByWithRelationInput } from '~/generated/graphql'; +import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions'; export function Opportunities() { const theme = useTheme(); + const [orderBy, setOrderBy] = useState< + PipelineProgressOrderByWithRelationInput[] + >(defaultPipelineProgressOrderBy); + + const updateSorts = useCallback( + (sorts: Array) => { + setOrderBy( + sorts.length + ? reduceSortsToOrderBy(sorts) + : defaultPipelineProgressOrderBy, + ); + }, + [], + ); + return ( } > - - + + diff --git a/front/src/pages/opportunities/opportunities-filters.tsx b/front/src/pages/opportunities/opportunities-filters.tsx new file mode 100644 index 000000000..7874e5859 --- /dev/null +++ b/front/src/pages/opportunities/opportunities-filters.tsx @@ -0,0 +1,37 @@ +import { FilterDropdownCompanySearchSelect } from '@/companies/components/FilterDropdownCompanySearchSelect'; +import { CompanyBoardContext } from '@/companies/states/CompanyBoardContext'; +import { FilterDefinitionByEntity } from '@/ui/filter-n-sort/types/FilterDefinitionByEntity'; +import { + IconBuildingSkyscraper, + IconCalendarEvent, + IconCurrencyDollar, +} from '@/ui/icon/index'; +import { icon } from '@/ui/themes/icon'; +import { PipelineProgress } from '~/generated/graphql'; + +export const opportunitiesFilters: FilterDefinitionByEntity[] = + [ + { + field: 'amount', + label: 'Amount', + icon: , + type: 'number', + }, + { + field: 'closeDate', + label: 'Close date', + icon: , + type: 'date', + }, + { + field: 'progressableId', + label: 'Company', + icon: ( + + ), + type: 'entity', + entitySelectComponent: ( + + ), + }, + ]; diff --git a/front/src/pages/opportunities/opportunities-sorts.tsx b/front/src/pages/opportunities/opportunities-sorts.tsx new file mode 100644 index 000000000..cb10872c3 --- /dev/null +++ b/front/src/pages/opportunities/opportunities-sorts.tsx @@ -0,0 +1,21 @@ +import { SortType } from '@/ui/filter-n-sort/types/interface'; +import { IconCalendarEvent, IconCurrencyDollar } from '@/ui/icon/index'; +import { PipelineProgressOrderByWithRelationInput as PipelineProgresses_Order_By } from '~/generated/graphql'; + +export const opportunitiesSorts = [ + { + key: 'createdAt', + label: 'Creation', + icon: , + }, + { + key: 'amount', + label: 'Amount', + icon: , + }, + { + key: 'closeDate', + label: 'Expected close date', + icon: , + }, +] satisfies Array>; diff --git a/front/src/modules/companies/components/companyBoardOptions.tsx b/front/src/pages/opportunities/opportunitiesBoardOptions.tsx similarity index 64% rename from front/src/modules/companies/components/companyBoardOptions.tsx rename to front/src/pages/opportunities/opportunitiesBoardOptions.tsx index 68c429b44..5f6a5aa94 100644 --- a/front/src/modules/companies/components/companyBoardOptions.tsx +++ b/front/src/pages/opportunities/opportunitiesBoardOptions.tsx @@ -3,11 +3,16 @@ import { NewCompanyProgressButton } from '@/companies/components/NewCompanyProgr import { BoardOptions } from '@/pipeline/types/BoardOptions'; import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope'; -export const companyBoardOptions: BoardOptions = { +import { opportunitiesFilters } from './opportunities-filters'; +import { opportunitiesSorts } from './opportunities-sorts'; + +export const opportunitiesBoardOptions: BoardOptions = { newCardComponent: ( ), cardComponent: , + filters: opportunitiesFilters, + sorts: opportunitiesSorts, }; diff --git a/front/src/pages/people/people-filters.tsx b/front/src/pages/people/people-filters.tsx index eff40c703..628e6d04d 100644 --- a/front/src/pages/people/people-filters.tsx +++ b/front/src/pages/people/people-filters.tsx @@ -8,6 +8,7 @@ import { IconPhone, IconUser, } from '@/ui/icon/index'; +import { TableContext } from '@/ui/table/states/TableContext'; import { icon } from '@/ui/themes/icon'; import { Person } from '~/generated/graphql'; @@ -37,7 +38,9 @@ export const peopleFilters: FilterDefinitionByEntity[] = [ ), type: 'entity', - entitySelectComponent: , + entitySelectComponent: ( + + ), }, { field: 'phone', diff --git a/front/src/testing/decorators.tsx b/front/src/testing/decorators.tsx index 7cb091045..f46c60899 100644 --- a/front/src/testing/decorators.tsx +++ b/front/src/testing/decorators.tsx @@ -3,9 +3,9 @@ import { ApolloProvider } from '@apollo/client'; import { Decorator } from '@storybook/react'; import { RecoilRoot } from 'recoil'; -import { pipeline } from '@/companies/__stories__/mock-data'; -import { HookCompanyBoard } from '@/companies/components/HookCompanyBoard'; +import { HooksCompanyBoard } from '@/companies/components/HooksCompanyBoard'; import { CompanyBoardContext } from '@/companies/states/CompanyBoardContext'; +import { defaultPipelineProgressOrderBy } from '@/pipeline/queries'; import { BoardCardContext } from '@/pipeline/states/BoardCardContext'; import { BoardColumnContext } from '@/pipeline/states/BoardColumnContext'; import { pipelineProgressIdScopedState } from '@/pipeline/states/pipelineProgressIdScopedState'; @@ -14,6 +14,7 @@ import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedSta import { CellContext } from '@/ui/table/states/CellContext'; import { RowContext } from '@/ui/table/states/RowContext'; +import { mockedPipelineProgressData } from './mock-data/pipeline-progress'; import { ComponentStorybookLayout } from './ComponentStorybookLayout'; import { mockedClient } from './mockedClient'; @@ -41,8 +42,11 @@ export const CellPositionDecorator: Decorator = (Story) => ( export const BoardDecorator: Decorator = (Story) => ( <> - + @@ -53,8 +57,7 @@ function HookLoadFakeBoardContextState() { pipelineProgressIdScopedState, BoardCardContext, ); - const pipelineProgress = - pipeline?.pipelineStages?.[0]?.pipelineProgresses?.[0]; + const pipelineProgress = mockedPipelineProgressData[1]; useEffect(() => { setPipelineProgressId(pipelineProgress?.id || ''); }, [pipelineProgress?.id, setPipelineProgressId]); @@ -64,8 +67,11 @@ function HookLoadFakeBoardContextState() { export const BoardCardDecorator: Decorator = (Story) => { return ( <> - + diff --git a/front/src/testing/mock-data/pipeline-progress.ts b/front/src/testing/mock-data/pipeline-progress.ts index f0f2cd0c8..ea16ce7ce 100644 --- a/front/src/testing/mock-data/pipeline-progress.ts +++ b/front/src/testing/mock-data/pipeline-progress.ts @@ -1,8 +1,17 @@ -import { PipelineProgress, User } from '../../generated/graphql'; +import { + PipelineProgress, + PipelineProgressableType, + User, +} from '../../generated/graphql'; type MockedPipelineProgress = Pick< PipelineProgress, - 'id' | 'amount' | 'closeDate' | 'progressableId' + | 'id' + | 'amount' + | 'closeDate' + | 'progressableId' + | 'pipelineStageId' + | 'progressableType' > & { accountOwner: Pick< User, @@ -31,13 +40,17 @@ export const mockedPipelineProgressData: Array = [ closeDate: '2021-10-01T00:00:00.000Z', progressableId: '0', accountOwner: accountOwner, + pipelineStageId: 'another-pipeline-stage-1', + progressableType: PipelineProgressableType.Company, }, { id: 'fe256b39-3ec3-4fe7-8998-b76aa0bfb600', progressableId: '89bb825c-171e-4bcc-9cf7-43448d6fb278', + pipelineStageId: 'fe256b39-3ec3-4fe3-8998-b76aa0bfb600', amount: 7, closeDate: '2021-10-01T00:00:00.000Z', accountOwner, + progressableType: PipelineProgressableType.Company, }, { id: '4a886c90-f4f2-4984-8222-882ebbb905d6', @@ -45,5 +58,7 @@ export const mockedPipelineProgressData: Array = [ amount: 100, closeDate: '2021-10-01T00:00:00.000Z', accountOwner, + pipelineStageId: 'fe256b39-3ec3-4fe3-8998-b76aa0bfb600', + progressableType: PipelineProgressableType.Company, }, ];