From e668d9ae51f40eef3d0536de25eb550448df459d Mon Sep 17 00:00:00 2001 From: Ayush Chothe Date: Fri, 6 Sep 2024 23:42:55 +0530 Subject: [PATCH] feat: add Cashfree Payment Provider --- .../customers/CustomerMainInfos.tsx | 9 + .../customers/addDrawer/AddCustomerDrawer.tsx | 9 +- .../addDrawer/ExternalAppsAccordion.tsx | 20 +- .../settings/integrations/AddAdyenDialog.tsx | 3 + .../integrations/AddCashfreeDialog.tsx | 279 ++++++++++ .../AddEditDeleteSuccessRedirectUrlDialog.tsx | 75 ++- .../integrations/AddGocardlessDialog.tsx | 3 + .../settings/integrations/AddStripeDialog.tsx | 3 + .../DeleteCashfreeIntegrationDialog.tsx | 85 +++ src/core/router/SettingRoutes.tsx | 24 + src/generated/graphql.tsx | 491 +++++++++++++++++- .../settings/CashfreeIntegrationDetails.tsx | 475 +++++++++++++++++ src/pages/settings/CashfreeIntegrations.tsx | 262 ++++++++++ src/pages/settings/Integrations.tsx | 33 ++ src/public/images/Cashfree.svg | 14 + translations/base.json | 17 +- 16 files changed, 1755 insertions(+), 47 deletions(-) create mode 100644 src/components/settings/integrations/AddCashfreeDialog.tsx create mode 100644 src/components/settings/integrations/DeleteCashfreeIntegrationDialog.tsx create mode 100644 src/pages/settings/CashfreeIntegrationDetails.tsx create mode 100644 src/pages/settings/CashfreeIntegrations.tsx create mode 100644 src/public/images/Cashfree.svg diff --git a/src/components/customers/CustomerMainInfos.tsx b/src/components/customers/CustomerMainInfos.tsx index 7cadc94fa..68180efc7 100644 --- a/src/components/customers/CustomerMainInfos.tsx +++ b/src/components/customers/CustomerMainInfos.tsx @@ -30,6 +30,7 @@ import { import { useInternationalization } from '~/hooks/core/useInternationalization' import Adyen from '~/public/images/adyen.svg' import Anrok from '~/public/images/anrok.svg' +import Cashfree from '~/public/images/cashfree.svg' import Gocardless from '~/public/images/gocardless.svg' import Hubspot from '~/public/images/hubspot.svg' import Netsuite from '~/public/images/netsuite.svg' @@ -126,6 +127,12 @@ gql` code } + ... on CashfreeProvider { + id + name + code + } + ... on AdyenProvider { id name @@ -436,6 +443,8 @@ export const CustomerMainInfos = ({ loading, customer, onEdit }: CustomerMainInf ) : paymentProvider === ProviderTypeEnum?.Adyen ? ( + ) : paymentProvider === ProviderTypeEnum?.Cashfree ? ( + ) : null} {linkedProvider?.name} diff --git a/src/components/customers/addDrawer/AddCustomerDrawer.tsx b/src/components/customers/addDrawer/AddCustomerDrawer.tsx index 904155c15..b72b913c5 100644 --- a/src/components/customers/addDrawer/AddCustomerDrawer.tsx +++ b/src/components/customers/addDrawer/AddCustomerDrawer.tsx @@ -44,6 +44,7 @@ import { NetsuiteCustomer, ProviderCustomer, ProviderPaymentMethodsEnum, + ProviderTypeEnum, TimezoneEnum, UpdateCustomerInput, XeroCustomer, @@ -139,9 +140,11 @@ export const AddCustomerDrawer = forwardRef((_, ref) => { return false } - // if syncWithProvider is false, providerCustomerId is required - if (!value?.syncWithProvider && !value?.providerCustomerId) { - return false + if (from?.[1].value.paymentProvider !== ProviderTypeEnum.Cashfree) { + // if syncWithProvider is false, providerCustomerId is required + if (!value?.syncWithProvider && !value?.providerCustomerId) { + return false + } } return true diff --git a/src/components/customers/addDrawer/ExternalAppsAccordion.tsx b/src/components/customers/addDrawer/ExternalAppsAccordion.tsx index c583cf418..ffafff871 100644 --- a/src/components/customers/addDrawer/ExternalAppsAccordion.tsx +++ b/src/components/customers/addDrawer/ExternalAppsAccordion.tsx @@ -52,6 +52,7 @@ import { import { useInternationalization } from '~/hooks/core/useInternationalization' import Adyen from '~/public/images/adyen.svg' import Anrok from '~/public/images/anrok.svg' +import Cashfree from '~/public/images/cashfree.svg' import GoCardless from '~/public/images/gocardless.svg' import Hubspot from '~/public/images/hubspot.svg' import Netsuite from '~/public/images/netsuite.svg' @@ -123,6 +124,13 @@ gql` code } + ... on CashfreeProvider { + __typename + id + name + code + } + ... on AdyenProvider { __typename id @@ -277,6 +285,14 @@ export const ExternalAppsAccordion = ({ formikProps, isEdition }: TExternalAppsA }) const isSyncWithProviderDisabled = !!formikProps.values.providerCustomer?.syncWithProvider + + const isSyncWithProviderSupported = useMemo(() => { + if (!formikProps.values.paymentProvider) return false + const unsupportedPaymentProviders: ProviderTypeEnum[] = [ProviderTypeEnum.Cashfree] + + return !unsupportedPaymentProviders.includes(formikProps.values.paymentProvider) + }, [formikProps.values.paymentProvider]) + const hadInitialNetsuiteIntegrationCustomer = !!formikProps.initialValues.integrationCustomers?.find( (i) => i.integrationType === IntegrationTypeEnum.Netsuite, @@ -473,6 +489,8 @@ export const ExternalAppsAccordion = ({ formikProps, isEdition }: TExternalAppsA ) : formikProps.values.paymentProvider === ProviderTypeEnum?.Adyen ? ( + ) : formikProps.values.paymentProvider === ProviderTypeEnum?.Cashfree ? ( + ) : null} ) : ( @@ -540,7 +558,7 @@ export const ExternalAppsAccordion = ({ formikProps, isEdition }: TExternalAppsA }} /> - {!!formikProps.values.paymentProviderCode && ( + {!!formikProps.values.paymentProviderCode && isSyncWithProviderSupported && ( <> + provider: AddCashfreeProviderDialogFragment + deleteDialogCallback: Function +}> + +export interface AddCashfreeDialogRef { + openDialog: (props?: TAddCashfreeDialogProps) => unknown + closeDialog: () => unknown +} + +export const AddCashfreeDialog = forwardRef((_, ref) => { + const navigate = useNavigate() + const dialogRef = useRef(null) + + const { translate } = useInternationalization() + const [localData, setLocalData] = useState(undefined) + const cashfreeProvider = localData?.provider + const isEdition = !!cashfreeProvider + + const [addApiKey] = useAddCashfreeApiKeyMutation({ + onCompleted({ addCashfreePaymentProvider }) { + if (addCashfreePaymentProvider?.id) { + navigate( + generatePath(CASHFREE_INTEGRATION_DETAILS_ROUTE, { + integrationId: addCashfreePaymentProvider.id, + }), + ) + + addToast({ + message: translate('text_17276219350329d36mgsotee'), + severity: 'success', + }) + } + }, + }) + + const [updateApiKey] = useUpdateCashfreeApiKeyMutation({ + onCompleted({ updateCashfreePaymentProvider }) { + if (updateCashfreePaymentProvider?.id) { + navigate( + generatePath(CASHFREE_INTEGRATION_DETAILS_ROUTE, { + integrationId: updateCashfreePaymentProvider.id, + }), + ) + + addToast({ + message: translate('text_1727621947600tg14usmdbb0'), + severity: 'success', + }) + } + }, + }) + + const [getCashfreeProviderByCode] = useGetProviderByCodeForCashfreeLazyQuery() + + const formikProps = useFormik({ + initialValues: { + code: cashfreeProvider?.code || '', + name: cashfreeProvider?.name || '', + clientId: cashfreeProvider?.clientId || '', + clientSecret: cashfreeProvider?.clientSecret || '', + }, + validationSchema: object().shape({ + name: string(), + code: string().required(''), + clientId: string().required(''), + clientSecret: string().required(''), + }), + onSubmit: async ({ clientId, clientSecret, ...values }, formikBag) => { + const res = await getCashfreeProviderByCode({ + context: { silentErrorCodes: [LagoApiError.NotFound] }, + variables: { + code: values.code, + }, + }) + const isNotAllowedToMutate = + (!!res.data?.paymentProvider?.id && !isEdition) || + (isEdition && + !!res.data?.paymentProvider?.id && + res.data?.paymentProvider?.id !== cashfreeProvider?.id) + + if (isNotAllowedToMutate) { + formikBag.setFieldError('code', translate('text_632a2d437e341dcc76817556')) + return + } + + if (isEdition) { + await updateApiKey({ + variables: { + input: { + id: cashfreeProvider?.id || '', + ...values, + }, + }, + }) + } else { + await addApiKey({ + variables: { + input: { clientId, clientSecret, ...values }, + }, + }) + } + dialogRef.current?.closeDialog() + }, + validateOnMount: true, + enableReinitialize: true, + }) + + useImperativeHandle(ref, () => ({ + openDialog: (data) => { + setLocalData(data) + dialogRef.current?.openDialog() + }, + closeDialog: () => dialogRef.current?.closeDialog(), + })) + + return ( + { + formikProps.resetForm() + }} + actions={({ closeDialog }) => ( + + {isEdition && ( + + )} + + + + + + )} + > +
+
+ + +
+ + +
+
+ ) +}) + +AddCashfreeDialog.displayName = 'AddCashfreeDialog' diff --git a/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx b/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx index 2069004d7..7ca82ba70 100644 --- a/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx +++ b/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx @@ -1,7 +1,6 @@ import { gql } from '@apollo/client' import { useFormik } from 'formik' import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react' -import styled from 'styled-components' import { object, string } from 'yup' import { Button, Dialog, DialogRef, Typography } from '~/components/designSystem' @@ -10,17 +9,19 @@ import { addToast, hasDefinedGQLError } from '~/core/apolloClient' import { ADYEN_SUCCESS_LINK_SPEC_URL } from '~/core/constants/externalUrls' import { AdyenForCreateAndEditSuccessRedirectUrlFragment, + CashfreeForCreateAndEditSuccessRedirectUrlFragment, GocardlessForCreateAndEditSuccessRedirectUrlFragment, StripeForCreateAndEditSuccessRedirectUrlFragment, UpdateAdyenPaymentProviderInput, + UpdateCashfreePaymentProviderInput, UpdateGocardlessPaymentProviderInput, UpdateStripePaymentProviderInput, useUpdateAdyenPaymentProviderMutation, + useUpdateCashfreePaymentProviderMutation, useUpdateGocardlessPaymentProviderMutation, useUpdateStripePaymentProviderMutation, } from '~/generated/graphql' import { useInternationalization } from '~/hooks/core/useInternationalization' -import { theme } from '~/styles' gql` fragment AdyenForCreateAndEditSuccessRedirectUrl on AdyenProvider { @@ -28,6 +29,11 @@ gql` successRedirectUrl } + fragment CashfreeForCreateAndEditSuccessRedirectUrl on CashfreeProvider { + id + successRedirectUrl + } + fragment gocardlessForCreateAndEditSuccessRedirectUrl on GocardlessProvider { id successRedirectUrl @@ -45,6 +51,13 @@ gql` } } + mutation updateCashfreePaymentProvider($input: UpdateCashfreePaymentProviderInput!) { + updateCashfreePaymentProvider(input: $input) { + id + successRedirectUrl + } + } + mutation updateGocardlessPaymentProvider($input: UpdateGocardlessPaymentProviderInput!) { updateGocardlessPaymentProvider(input: $input) { id @@ -70,6 +83,7 @@ const AddEditDeleteSuccessRedirectUrlDialogProviderType = { Adyen: 'Adyen', Stripe: 'Stripe', GoCardless: 'GoCardless', + Cashfree: 'Cashfree', } as const type LocalProviderType = { @@ -77,6 +91,7 @@ type LocalProviderType = { type: keyof typeof AddEditDeleteSuccessRedirectUrlDialogProviderType provider?: | AdyenForCreateAndEditSuccessRedirectUrlFragment + | CashfreeForCreateAndEditSuccessRedirectUrlFragment | GocardlessForCreateAndEditSuccessRedirectUrlFragment | StripeForCreateAndEditSuccessRedirectUrlFragment | null @@ -110,6 +125,17 @@ export const AddEditDeleteSuccessRedirectUrlDialog = }, }) + const [updateCashfreeProvider] = useUpdateCashfreePaymentProviderMutation({ + onCompleted(data) { + if (data && data.updateCashfreePaymentProvider) { + addToast({ + message: successToastMessage, + severity: 'success', + }) + } + }, + }) + const [updateGocardlessProvider] = useUpdateGocardlessPaymentProviderMutation({ onCompleted(data) { if (data && data.updateGocardlessPaymentProvider) { @@ -134,6 +160,7 @@ export const AddEditDeleteSuccessRedirectUrlDialog = const formikProps = useFormik< | UpdateAdyenPaymentProviderInput + | UpdateCashfreePaymentProviderInput | UpdateGocardlessPaymentProviderInput | UpdateStripePaymentProviderInput >({ @@ -151,6 +178,7 @@ export const AddEditDeleteSuccessRedirectUrlDialog = [AddEditDeleteSuccessRedirectUrlDialogProviderType.Adyen]: updateAdyenProvider, [AddEditDeleteSuccessRedirectUrlDialogProviderType.Stripe]: updateStripeProvider, [AddEditDeleteSuccessRedirectUrlDialogProviderType.GoCardless]: updateGocardlessProvider, + [AddEditDeleteSuccessRedirectUrlDialogProviderType.Cashfree]: updateCashfreeProvider, } const method = methodLoojup[localData?.type as LocalProviderType['type']] @@ -255,35 +283,26 @@ export const AddEditDeleteSuccessRedirectUrlDialog = )} > {localData?.mode !== AddEditDeleteSuccessRedirectUrlDialogMode.Delete && ( - - - } - formikProps={formikProps} - /> - + + } + formikProps={formikProps} + /> )} ) }) -const Content = styled.div` - margin-bottom: ${theme.spacing(8)}; - - > *:not(:last-child) { - margin-bottom: ${theme.spacing(6)}; - } -` - AddEditDeleteSuccessRedirectUrlDialog.displayName = 'forwardRef' diff --git a/src/components/settings/integrations/AddGocardlessDialog.tsx b/src/components/settings/integrations/AddGocardlessDialog.tsx index e5625e1aa..dfef5f987 100644 --- a/src/components/settings/integrations/AddGocardlessDialog.tsx +++ b/src/components/settings/integrations/AddGocardlessDialog.tsx @@ -37,6 +37,9 @@ gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on AdyenProvider { id } diff --git a/src/components/settings/integrations/AddStripeDialog.tsx b/src/components/settings/integrations/AddStripeDialog.tsx index e0f4769b0..ba4aad415 100644 --- a/src/components/settings/integrations/AddStripeDialog.tsx +++ b/src/components/settings/integrations/AddStripeDialog.tsx @@ -41,6 +41,9 @@ gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on AdyenProvider { id } diff --git a/src/components/settings/integrations/DeleteCashfreeIntegrationDialog.tsx b/src/components/settings/integrations/DeleteCashfreeIntegrationDialog.tsx new file mode 100644 index 000000000..77a928b6b --- /dev/null +++ b/src/components/settings/integrations/DeleteCashfreeIntegrationDialog.tsx @@ -0,0 +1,85 @@ +import { gql } from '@apollo/client' +import { forwardRef, useImperativeHandle, useRef, useState } from 'react' + +import { WarningDialog, WarningDialogRef } from '~/components/WarningDialog' +import { addToast } from '~/core/apolloClient' +import { + DeleteCashfreeIntegrationDialogFragment, + useDeleteCashfreeMutation, +} from '~/generated/graphql' +import { useInternationalization } from '~/hooks/core/useInternationalization' + +gql` + fragment DeleteCashfreeIntegrationDialog on CashfreeProvider { + id + name + } + + mutation deleteCashfree($input: DestroyPaymentProviderInput!) { + destroyPaymentProvider(input: $input) { + id + } + } +` + +type TDeleteCashfreeIntegrationDialogProps = { + provider: DeleteCashfreeIntegrationDialogFragment | null + callback?: Function +} + +export interface DeleteCashfreeIntegrationDialogRef { + openDialog: ({ provider, callback }: TDeleteCashfreeIntegrationDialogProps) => unknown + closeDialog: () => unknown +} + +export const DeleteCashfreeIntegrationDialog = forwardRef( + (_, ref) => { + const { translate } = useInternationalization() + + const dialogRef = useRef(null) + const [localData, setLocalData] = useState( + undefined, + ) + + const cashfreeProvider = localData?.provider + + const [deleteCashfree] = useDeleteCashfreeMutation({ + onCompleted(data) { + if (data && data.destroyPaymentProvider) { + dialogRef.current?.closeDialog() + localData?.callback?.() + addToast({ + message: translate('text_1727621949511zk6kkl99pzk'), + severity: 'success', + }) + } + }, + update(cache) { + cache.evict({ id: `CashfreeProvider:${cashfreeProvider?.id}` }) + }, + }) + + useImperativeHandle(ref, () => ({ + openDialog: (data) => { + setLocalData(data) + dialogRef.current?.openDialog() + }, + closeDialog: () => dialogRef.current?.closeDialog(), + })) + + return ( + + await deleteCashfree({ variables: { input: { id: cashfreeProvider?.id as string } } }) + } + continueText={translate('text_659d5de7c9b7f51394f7f3fd')} + /> + ) + }, +) + +DeleteCashfreeIntegrationDialog.displayName = 'DeleteCashfreeIntegrationDialog' diff --git a/src/core/router/SettingRoutes.tsx b/src/core/router/SettingRoutes.tsx index cfce39fc2..2f9f64148 100644 --- a/src/core/router/SettingRoutes.tsx +++ b/src/core/router/SettingRoutes.tsx @@ -74,6 +74,16 @@ const StripeIntegrationDetails = lazyLoad( /* webpackChunkName: 'stripe-integration-details' */ '~/pages/settings/StripeIntegrationDetails' ), ) +const CashfreeIntegrations = lazyLoad( + () => + import(/* webpackChunkName: 'cashfree-integrations' */ '~/pages/settings/CashfreeIntegrations'), +) +const CashfreeIntegrationDetails = lazyLoad( + () => + import( + /* webpackChunkName: 'cashfree-integration-details' */ '~/pages/settings/CashfreeIntegrationDetails' + ), +) const GocardlessIntegrationOauthCallback = lazyLoad( () => import( @@ -139,6 +149,8 @@ export const NETSUITE_INTEGRATION_ROUTE = `${INTEGRATIONS_ROUTE}/netsuite` export const NETSUITE_INTEGRATION_DETAILS_ROUTE = `${INTEGRATIONS_ROUTE}/netsuite/:integrationId/:tab` export const STRIPE_INTEGRATION_ROUTE = `${INTEGRATIONS_ROUTE}/stripe` export const STRIPE_INTEGRATION_DETAILS_ROUTE = `${INTEGRATIONS_ROUTE}/stripe/:integrationId` +export const CASHFREE_INTEGRATION_ROUTE = `${INTEGRATIONS_ROUTE}/cashfree` +export const CASHFREE_INTEGRATION_DETAILS_ROUTE = `${INTEGRATIONS_ROUTE}/cashfree/:integrationId` export const GOCARDLESS_INTEGRATION_ROUTE = `${INTEGRATIONS_ROUTE}/gocardless` export const GOCARDLESS_INTEGRATION_OAUTH_CALLBACK_ROUTE = `${INTEGRATIONS_ROUTE}/gocardless/callback` export const GOCARDLESS_INTEGRATION_DETAILS_ROUTE = `${INTEGRATIONS_ROUTE}/gocardless/:integrationId` @@ -270,6 +282,18 @@ export const settingRoutes: CustomRouteObject[] = [ element: , permissions: ['organizationIntegrationsView'], }, + { + path: CASHFREE_INTEGRATION_ROUTE, + private: true, + element: , + permissions: ['organizationIntegrationsView'], + }, + { + path: CASHFREE_INTEGRATION_DETAILS_ROUTE, + private: true, + element: , + permissions: ['organizationIntegrationsView'], + }, { path: GOCARDLESS_INTEGRATION_ROUTE, private: true, diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index d6c10cb9b..088ccaff0 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -49,6 +49,17 @@ export type AddAdyenPaymentProviderInput = { successRedirectUrl?: InputMaybe; }; +/** Cashfree input arguments */ +export type AddCashfreePaymentProviderInput = { + clientId: Scalars['String']['input']; + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: InputMaybe; + clientSecret: Scalars['String']['input']; + code: Scalars['String']['input']; + name: Scalars['String']['input']; + successRedirectUrl?: InputMaybe; +}; + /** Gocardless input arguments */ export type AddGocardlessPaymentProviderInput = { accessCode?: InputMaybe; @@ -283,6 +294,16 @@ export enum BillingTimeEnum { Calendar = 'calendar' } +export type CashfreeProvider = { + __typename?: 'CashfreeProvider'; + clientId?: Maybe; + clientSecret?: Maybe; + code: Scalars['String']['output']; + id: Scalars['ID']['output']; + name: Scalars['String']['output']; + successRedirectUrl?: Maybe; +}; + export type Charge = { __typename?: 'Charge'; billableMetric: BillableMetric; @@ -1754,6 +1775,7 @@ export type CurrentOrganization = { adyenPaymentProviders?: Maybe>; apiKey?: Maybe; billingConfiguration?: Maybe; + cashfreePaymentProviders?: Maybe>; city?: Maybe; country?: Maybe; createdAt: Scalars['ISO8601DateTime']['output']; @@ -3103,6 +3125,8 @@ export type Mutation = { acceptInvite?: Maybe; /** Add Adyen payment provider */ addAdyenPaymentProvider?: Maybe; + /** Add or update Cashfree payment provider */ + addCashfreePaymentProvider?: Maybe; /** Add or update Gocardless payment provider */ addGocardlessPaymentProvider?: Maybe; /** Add Stripe API keys to the organization */ @@ -3265,6 +3289,8 @@ export type Mutation = { updateAnrokIntegration?: Maybe; /** Updates an existing Billable metric */ updateBillableMetric?: Maybe; + /** Update Cashfree payment provider */ + updateCashfreePaymentProvider?: Maybe; /** Update an existing coupon */ updateCoupon?: Maybe; /** Updates an existing Credit Note */ @@ -3328,6 +3354,11 @@ export type MutationAddAdyenPaymentProviderArgs = { }; +export type MutationAddCashfreePaymentProviderArgs = { + input: AddCashfreePaymentProviderInput; +}; + + export type MutationAddGocardlessPaymentProviderArgs = { input: AddGocardlessPaymentProviderInput; }; @@ -3738,6 +3769,11 @@ export type MutationUpdateBillableMetricArgs = { }; +export type MutationUpdateCashfreePaymentProviderArgs = { + input: UpdateCashfreePaymentProviderInput; +}; + + export type MutationUpdateCouponArgs = { input: UpdateCouponInput; }; @@ -3970,7 +4006,7 @@ export type OverdueBalanceCollection = { metadata: CollectionMetadata; }; -export type PaymentProvider = AdyenProvider | GocardlessProvider | StripeProvider; +export type PaymentProvider = AdyenProvider | CashfreeProvider | GocardlessProvider | StripeProvider; /** PaymentProviderCollection type */ export type PaymentProviderCollection = { @@ -4214,6 +4250,7 @@ export enum ProviderPaymentMethodsEnum { export enum ProviderTypeEnum { Adyen = 'adyen', + Cashfree = 'cashfree', Gocardless = 'gocardless', Stripe = 'stripe' } @@ -5396,6 +5433,16 @@ export type UpdateBillableMetricInput = { weightedInterval?: InputMaybe; }; +/** Update input arguments */ +export type UpdateCashfreePaymentProviderInput = { + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: InputMaybe; + code?: InputMaybe; + id: Scalars['ID']['input']; + name?: InputMaybe; + successRedirectUrl?: InputMaybe; +}; + /** Autogenerated input type of UpdateCoupon */ export type UpdateCouponInput = { amountCents?: InputMaybe; @@ -6230,7 +6277,7 @@ export type PaymentProvidersListForCustomerMainInfosQueryVariables = Exact<{ }>; -export type PaymentProvidersListForCustomerMainInfosQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string, name: string, code: string } | { __typename?: 'GocardlessProvider', id: string, name: string, code: string } | { __typename?: 'StripeProvider', id: string, name: string, code: string }> } | null }; +export type PaymentProvidersListForCustomerMainInfosQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string, name: string, code: string } | { __typename?: 'CashfreeProvider', id: string, name: string, code: string } | { __typename?: 'GocardlessProvider', id: string, name: string, code: string } | { __typename?: 'StripeProvider', id: string, name: string, code: string }> } | null }; export type IntegrationsListForCustomerMainInfosQueryVariables = Exact<{ limit?: InputMaybe; @@ -6347,7 +6394,7 @@ export type PaymentProvidersListForCustomerCreateEditExternalAppsAccordionQueryV }>; -export type PaymentProvidersListForCustomerCreateEditExternalAppsAccordionQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename: 'AdyenProvider', id: string, name: string, code: string } | { __typename: 'GocardlessProvider', id: string, name: string, code: string } | { __typename: 'StripeProvider', id: string, name: string, code: string }> } | null }; +export type PaymentProvidersListForCustomerCreateEditExternalAppsAccordionQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename: 'AdyenProvider', id: string, name: string, code: string } | { __typename: 'CashfreeProvider', id: string, name: string, code: string } | { __typename: 'GocardlessProvider', id: string, name: string, code: string } | { __typename: 'StripeProvider', id: string, name: string, code: string }> } | null }; export type AccountingIntegrationsListForCustomerEditExternalAppsAccordionQueryVariables = Exact<{ limit?: InputMaybe; @@ -6908,7 +6955,7 @@ export type GetProviderByCodeForAdyenQueryVariables = Exact<{ }>; -export type GetProviderByCodeForAdyenQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; +export type GetProviderByCodeForAdyenQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'CashfreeProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; export type AddAdyenApiKeyMutationVariables = Exact<{ input: AddAdyenPaymentProviderInput; @@ -6940,8 +6987,33 @@ export type UpdateAnrokIntegrationMutationVariables = Exact<{ export type UpdateAnrokIntegrationMutation = { __typename?: 'Mutation', updateAnrokIntegration?: { __typename?: 'AnrokIntegration', id: string, name: string, code: string, apiKey: string } | null }; +export type AddCashfreeProviderDialogFragment = { __typename?: 'CashfreeProvider', id: string, name: string, code: string, clientId?: string | null, clientSecret?: string | null }; + +export type GetProviderByCodeForCashfreeQueryVariables = Exact<{ + code?: InputMaybe; +}>; + + +export type GetProviderByCodeForCashfreeQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'CashfreeProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; + +export type AddCashfreeApiKeyMutationVariables = Exact<{ + input: AddCashfreePaymentProviderInput; +}>; + + +export type AddCashfreeApiKeyMutation = { __typename?: 'Mutation', addCashfreePaymentProvider?: { __typename?: 'CashfreeProvider', id: string, name: string, code: string, clientId?: string | null, clientSecret?: string | null, successRedirectUrl?: string | null } | null }; + +export type UpdateCashfreeApiKeyMutationVariables = Exact<{ + input: UpdateCashfreePaymentProviderInput; +}>; + + +export type UpdateCashfreeApiKeyMutation = { __typename?: 'Mutation', updateCashfreePaymentProvider?: { __typename?: 'CashfreeProvider', id: string, name: string, code: string, clientId?: string | null, clientSecret?: string | null, successRedirectUrl?: string | null } | null }; + export type AdyenForCreateAndEditSuccessRedirectUrlFragment = { __typename?: 'AdyenProvider', id: string, successRedirectUrl?: string | null }; +export type CashfreeForCreateAndEditSuccessRedirectUrlFragment = { __typename?: 'CashfreeProvider', id: string, successRedirectUrl?: string | null }; + export type GocardlessForCreateAndEditSuccessRedirectUrlFragment = { __typename?: 'GocardlessProvider', id: string, successRedirectUrl?: string | null }; export type StripeForCreateAndEditSuccessRedirectUrlFragment = { __typename?: 'StripeProvider', id: string, successRedirectUrl?: string | null }; @@ -6953,6 +7025,13 @@ export type UpdateAdyenPaymentProviderMutationVariables = Exact<{ export type UpdateAdyenPaymentProviderMutation = { __typename?: 'Mutation', updateAdyenPaymentProvider?: { __typename?: 'AdyenProvider', id: string, successRedirectUrl?: string | null } | null }; +export type UpdateCashfreePaymentProviderMutationVariables = Exact<{ + input: UpdateCashfreePaymentProviderInput; +}>; + + +export type UpdateCashfreePaymentProviderMutation = { __typename?: 'Mutation', updateCashfreePaymentProvider?: { __typename?: 'CashfreeProvider', id: string, successRedirectUrl?: string | null } | null }; + export type UpdateGocardlessPaymentProviderMutationVariables = Exact<{ input: UpdateGocardlessPaymentProviderInput; }>; @@ -6974,7 +7053,7 @@ export type GetProviderByCodeForGocardlessQueryVariables = Exact<{ }>; -export type GetProviderByCodeForGocardlessQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; +export type GetProviderByCodeForGocardlessQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'CashfreeProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; export type UpdateGocardlessApiKeyMutationVariables = Exact<{ input: UpdateGocardlessPaymentProviderInput; @@ -7029,7 +7108,7 @@ export type GetProviderByCodeForStripeQueryVariables = Exact<{ }>; -export type GetProviderByCodeForStripeQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; +export type GetProviderByCodeForStripeQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string } | { __typename?: 'CashfreeProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string } | null }; export type AddStripeApiKeyMutationVariables = Exact<{ input: AddStripePaymentProviderInput; @@ -7179,6 +7258,15 @@ export type DestroyNangoIntegrationMutationVariables = Exact<{ export type DestroyNangoIntegrationMutation = { __typename?: 'Mutation', destroyIntegration?: { __typename?: 'DestroyIntegrationPayload', id?: string | null } | null }; +export type DeleteCashfreeIntegrationDialogFragment = { __typename?: 'CashfreeProvider', id: string, name: string }; + +export type DeleteCashfreeMutationVariables = Exact<{ + input: DestroyPaymentProviderInput; +}>; + + +export type DeleteCashfreeMutation = { __typename?: 'Mutation', destroyPaymentProvider?: { __typename?: 'DestroyPaymentProviderPayload', id?: string | null } | null }; + export type DeleteGocardlessIntegrationDialogFragment = { __typename?: 'GocardlessProvider', id: string, name: string }; export type DeleteGocardlessMutationVariables = Exact<{ @@ -8294,7 +8382,7 @@ export type GetAdyenIntegrationsDetailsQueryVariables = Exact<{ }>; -export type GetAdyenIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string, apiKey?: string | null, code: string, hmacKey?: string | null, livePrefix?: string | null, merchantAccount?: string | null, successRedirectUrl?: string | null, name: string } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' }> } | null }; +export type GetAdyenIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider', id: string, apiKey?: string | null, code: string, hmacKey?: string | null, livePrefix?: string | null, merchantAccount?: string | null, successRedirectUrl?: string | null, name: string } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' }> } | null }; export type AdyenIntegrationsFragment = { __typename?: 'AdyenProvider', id: string, name: string, code: string }; @@ -8304,7 +8392,7 @@ export type GetAdyenIntegrationsListQueryVariables = Exact<{ }>; -export type GetAdyenIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string, name: string, code: string, apiKey?: string | null, hmacKey?: string | null, livePrefix?: string | null, merchantAccount?: string | null } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' }> } | null }; +export type GetAdyenIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string, name: string, code: string, apiKey?: string | null, hmacKey?: string | null, livePrefix?: string | null, merchantAccount?: string | null } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' }> } | null }; export type AnrokIntegrationDetailsFragment = { __typename?: 'AnrokIntegration', id: string, name: string, code: string, apiKey: string }; @@ -8343,6 +8431,27 @@ export type GetOktaIntegrationQueryVariables = Exact<{ export type GetOktaIntegrationQuery = { __typename?: 'Query', integration?: { __typename?: 'AnrokIntegration' } | { __typename?: 'HubspotIntegration' } | { __typename?: 'NetsuiteIntegration' } | { __typename?: 'OktaIntegration', id: string, clientId?: string | null, clientSecret?: string | null, code: string, organizationName: string, domain: string, name: string } | { __typename?: 'XeroIntegration' } | null }; +export type CashfreeIntegrationDetailsFragment = { __typename?: 'CashfreeProvider', id: string, code: string, name: string, clientId?: string | null, clientSecret?: string | null, successRedirectUrl?: string | null }; + +export type GetCashfreeIntegrationsDetailsQueryVariables = Exact<{ + id: Scalars['ID']['input']; + limit?: InputMaybe; + type?: InputMaybe; +}>; + + +export type GetCashfreeIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider', id: string, code: string, name: string, clientId?: string | null, clientSecret?: string | null, successRedirectUrl?: string | null } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider', id: string } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' }> } | null }; + +export type CashfreeIntegrationsFragment = { __typename?: 'CashfreeProvider', id: string, name: string, code: string }; + +export type GetCashfreeIntegrationsListQueryVariables = Exact<{ + limit?: InputMaybe; + type?: InputMaybe; +}>; + + +export type GetCashfreeIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider', id: string, name: string, code: string, clientId?: string | null, clientSecret?: string | null } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider' }> } | null }; + export type CreateDunningCampaignMutationVariables = Exact<{ input: CreateDunningCampaignInput; }>; @@ -8353,7 +8462,7 @@ export type CreateDunningCampaignMutation = { __typename?: 'Mutation', createDun export type CreateDunningCampaignPaymentProviderQueryVariables = Exact<{ [key: string]: never; }>; -export type CreateDunningCampaignPaymentProviderQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename: 'AdyenProvider' } | { __typename: 'GocardlessProvider' } | { __typename: 'StripeProvider' }> } | null }; +export type CreateDunningCampaignPaymentProviderQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename: 'AdyenProvider' } | { __typename: 'CashfreeProvider' } | { __typename: 'GocardlessProvider' } | { __typename: 'StripeProvider' }> } | null }; export type DunningCampaignItemFragment = { __typename?: 'DunningCampaign', id: string, name: string, code: string, appliedToOrganization: boolean }; @@ -8381,7 +8490,7 @@ export type GetGocardlessIntegrationsDetailsQueryVariables = Exact<{ }>; -export type GetGocardlessIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider' } | { __typename?: 'GocardlessProvider', id: string, code: string, name: string, successRedirectUrl?: string | null, webhookSecret?: string | null } | { __typename?: 'StripeProvider' } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider' }> } | null }; +export type GetGocardlessIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider', id: string, code: string, name: string, successRedirectUrl?: string | null, webhookSecret?: string | null } | { __typename?: 'StripeProvider' } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider' }> } | null }; export type GocardlessIntegrationOauthCallbackFragment = { __typename?: 'GocardlessProvider', id: string, name: string, code: string }; @@ -8400,7 +8509,7 @@ export type GetGocardlessIntegrationsListQueryVariables = Exact<{ }>; -export type GetGocardlessIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'GocardlessProvider', id: string, name: string, code: string } | { __typename?: 'StripeProvider' }> } | null }; +export type GetGocardlessIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider', id: string, name: string, code: string } | { __typename?: 'StripeProvider' }> } | null }; export type HubspotIntegrationDetailsFragment = { __typename?: 'HubspotIntegration', id: string, name: string, code: string, defaultTargetedObject: HubspotTargetedObjectsEnum, syncInvoices?: boolean | null, syncSubscriptions?: boolean | null }; @@ -8428,7 +8537,7 @@ export type IntegrationsSettingQueryVariables = Exact<{ }>; -export type IntegrationsSettingQuery = { __typename?: 'Query', organization?: { __typename?: 'CurrentOrganization', id: string, euTaxManagement: boolean, country?: CountryCode | null } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string }> } | null, integrations?: { __typename?: 'IntegrationCollection', collection: Array<{ __typename?: 'AnrokIntegration', id: string } | { __typename?: 'HubspotIntegration', id: string } | { __typename?: 'NetsuiteIntegration', id: string } | { __typename?: 'OktaIntegration' } | { __typename?: 'XeroIntegration', id: string }> } | null }; +export type IntegrationsSettingQuery = { __typename?: 'Query', organization?: { __typename?: 'CurrentOrganization', id: string, euTaxManagement: boolean, country?: CountryCode | null } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider', id: string } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider', id: string } | { __typename?: 'StripeProvider', id: string }> } | null, integrations?: { __typename?: 'IntegrationCollection', collection: Array<{ __typename?: 'AnrokIntegration', id: string } | { __typename?: 'HubspotIntegration', id: string } | { __typename?: 'NetsuiteIntegration', id: string } | { __typename?: 'OktaIntegration' } | { __typename?: 'XeroIntegration', id: string }> } | null }; export type GetOrganizationSettingsQueryVariables = Exact<{ appliedToOrganization?: InputMaybe; @@ -8511,7 +8620,7 @@ export type GetStripeIntegrationsDetailsQueryVariables = Exact<{ }>; -export type GetStripeIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider', id: string, code: string, name: string, secretKey?: string | null, successRedirectUrl?: string | null } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider', id: string }> } | null }; +export type GetStripeIntegrationsDetailsQuery = { __typename?: 'Query', paymentProvider?: { __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider', id: string, code: string, name: string, secretKey?: string | null, successRedirectUrl?: string | null } | null, paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider', id: string }> } | null }; export type StripeIntegrationsFragment = { __typename?: 'StripeProvider', id: string, name: string, code: string }; @@ -8521,7 +8630,7 @@ export type GetStripeIntegrationsListQueryVariables = Exact<{ }>; -export type GetStripeIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider', id: string, name: string, code: string, secretKey?: string | null }> } | null }; +export type GetStripeIntegrationsListQuery = { __typename?: 'Query', paymentProviders?: { __typename?: 'PaymentProviderCollection', collection: Array<{ __typename?: 'AdyenProvider' } | { __typename?: 'CashfreeProvider' } | { __typename?: 'GocardlessProvider' } | { __typename?: 'StripeProvider', id: string, name: string, code: string, secretKey?: string | null }> } | null }; export type TaxItemForTaxSettingsFragment = { __typename?: 'Tax', id: string, code: string, name: string, rate: number, autoGenerated: boolean, customersCount: number }; @@ -9332,12 +9441,27 @@ export const AddAdyenProviderDialogFragmentDoc = gql` merchantAccount } `; +export const AddCashfreeProviderDialogFragmentDoc = gql` + fragment AddCashfreeProviderDialog on CashfreeProvider { + id + name + code + clientId + clientSecret +} + `; export const AdyenForCreateAndEditSuccessRedirectUrlFragmentDoc = gql` fragment AdyenForCreateAndEditSuccessRedirectUrl on AdyenProvider { id successRedirectUrl } `; +export const CashfreeForCreateAndEditSuccessRedirectUrlFragmentDoc = gql` + fragment CashfreeForCreateAndEditSuccessRedirectUrl on CashfreeProvider { + id + successRedirectUrl +} + `; export const GocardlessForCreateAndEditSuccessRedirectUrlFragmentDoc = gql` fragment gocardlessForCreateAndEditSuccessRedirectUrl on GocardlessProvider { id @@ -9443,6 +9567,12 @@ export const DeleteAdyenIntegrationDialogFragmentDoc = gql` name } `; +export const DeleteCashfreeIntegrationDialogFragmentDoc = gql` + fragment DeleteCashfreeIntegrationDialog on CashfreeProvider { + id + name +} + `; export const DeleteGocardlessIntegrationDialogFragmentDoc = gql` fragment DeleteGocardlessIntegrationDialog on GocardlessProvider { id @@ -11221,6 +11351,23 @@ export const OktaIntegrationDetailsFragmentDoc = gql` name } `; +export const CashfreeIntegrationDetailsFragmentDoc = gql` + fragment CashfreeIntegrationDetails on CashfreeProvider { + id + code + name + clientId + clientSecret + successRedirectUrl +} + `; +export const CashfreeIntegrationsFragmentDoc = gql` + fragment CashfreeIntegrations on CashfreeProvider { + id + name + code +} + `; export const DunningCampaignItemFragmentDoc = gql` fragment DunningCampaignItem on DunningCampaign { id @@ -12796,6 +12943,11 @@ export const PaymentProvidersListForCustomerMainInfosDocument = gql` name code } + ... on CashfreeProvider { + id + name + code + } ... on AdyenProvider { id name @@ -13352,6 +13504,12 @@ export const PaymentProvidersListForCustomerCreateEditExternalAppsAccordionDocum name code } + ... on CashfreeProvider { + __typename + id + name + code + } ... on AdyenProvider { __typename id @@ -15638,6 +15796,9 @@ export const GetProviderByCodeForAdyenDocument = gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on StripeProvider { id } @@ -15821,6 +15982,129 @@ export function useUpdateAnrokIntegrationMutation(baseOptions?: Apollo.MutationH export type UpdateAnrokIntegrationMutationHookResult = ReturnType; export type UpdateAnrokIntegrationMutationResult = Apollo.MutationResult; export type UpdateAnrokIntegrationMutationOptions = Apollo.BaseMutationOptions; +export const GetProviderByCodeForCashfreeDocument = gql` + query getProviderByCodeForCashfree($code: String) { + paymentProvider(code: $code) { + ... on CashfreeProvider { + id + } + ... on GocardlessProvider { + id + } + ... on AdyenProvider { + id + } + ... on StripeProvider { + id + } + } +} + `; + +/** + * __useGetProviderByCodeForCashfreeQuery__ + * + * To run a query within a React component, call `useGetProviderByCodeForCashfreeQuery` and pass it any options that fit your needs. + * When your component renders, `useGetProviderByCodeForCashfreeQuery` 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 } = useGetProviderByCodeForCashfreeQuery({ + * variables: { + * code: // value for 'code' + * }, + * }); + */ +export function useGetProviderByCodeForCashfreeQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetProviderByCodeForCashfreeDocument, options); + } +export function useGetProviderByCodeForCashfreeLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetProviderByCodeForCashfreeDocument, options); + } +export function useGetProviderByCodeForCashfreeSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(GetProviderByCodeForCashfreeDocument, options); + } +export type GetProviderByCodeForCashfreeQueryHookResult = ReturnType; +export type GetProviderByCodeForCashfreeLazyQueryHookResult = ReturnType; +export type GetProviderByCodeForCashfreeSuspenseQueryHookResult = ReturnType; +export type GetProviderByCodeForCashfreeQueryResult = Apollo.QueryResult; +export const AddCashfreeApiKeyDocument = gql` + mutation addCashfreeApiKey($input: AddCashfreePaymentProviderInput!) { + addCashfreePaymentProvider(input: $input) { + id + ...AddCashfreeProviderDialog + ...CashfreeIntegrationDetails + } +} + ${AddCashfreeProviderDialogFragmentDoc} +${CashfreeIntegrationDetailsFragmentDoc}`; +export type AddCashfreeApiKeyMutationFn = Apollo.MutationFunction; + +/** + * __useAddCashfreeApiKeyMutation__ + * + * To run a mutation, you first call `useAddCashfreeApiKeyMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useAddCashfreeApiKeyMutation` 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 [addCashfreeApiKeyMutation, { data, loading, error }] = useAddCashfreeApiKeyMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useAddCashfreeApiKeyMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(AddCashfreeApiKeyDocument, options); + } +export type AddCashfreeApiKeyMutationHookResult = ReturnType; +export type AddCashfreeApiKeyMutationResult = Apollo.MutationResult; +export type AddCashfreeApiKeyMutationOptions = Apollo.BaseMutationOptions; +export const UpdateCashfreeApiKeyDocument = gql` + mutation updateCashfreeApiKey($input: UpdateCashfreePaymentProviderInput!) { + updateCashfreePaymentProvider(input: $input) { + id + ...AddCashfreeProviderDialog + ...CashfreeIntegrationDetails + } +} + ${AddCashfreeProviderDialogFragmentDoc} +${CashfreeIntegrationDetailsFragmentDoc}`; +export type UpdateCashfreeApiKeyMutationFn = Apollo.MutationFunction; + +/** + * __useUpdateCashfreeApiKeyMutation__ + * + * To run a mutation, you first call `useUpdateCashfreeApiKeyMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateCashfreeApiKeyMutation` 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 [updateCashfreeApiKeyMutation, { data, loading, error }] = useUpdateCashfreeApiKeyMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useUpdateCashfreeApiKeyMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateCashfreeApiKeyDocument, options); + } +export type UpdateCashfreeApiKeyMutationHookResult = ReturnType; +export type UpdateCashfreeApiKeyMutationResult = Apollo.MutationResult; +export type UpdateCashfreeApiKeyMutationOptions = Apollo.BaseMutationOptions; export const UpdateAdyenPaymentProviderDocument = gql` mutation updateAdyenPaymentProvider($input: UpdateAdyenPaymentProviderInput!) { updateAdyenPaymentProvider(input: $input) { @@ -15855,6 +16139,40 @@ export function useUpdateAdyenPaymentProviderMutation(baseOptions?: Apollo.Mutat export type UpdateAdyenPaymentProviderMutationHookResult = ReturnType; export type UpdateAdyenPaymentProviderMutationResult = Apollo.MutationResult; export type UpdateAdyenPaymentProviderMutationOptions = Apollo.BaseMutationOptions; +export const UpdateCashfreePaymentProviderDocument = gql` + mutation updateCashfreePaymentProvider($input: UpdateCashfreePaymentProviderInput!) { + updateCashfreePaymentProvider(input: $input) { + id + successRedirectUrl + } +} + `; +export type UpdateCashfreePaymentProviderMutationFn = Apollo.MutationFunction; + +/** + * __useUpdateCashfreePaymentProviderMutation__ + * + * To run a mutation, you first call `useUpdateCashfreePaymentProviderMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateCashfreePaymentProviderMutation` 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 [updateCashfreePaymentProviderMutation, { data, loading, error }] = useUpdateCashfreePaymentProviderMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useUpdateCashfreePaymentProviderMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateCashfreePaymentProviderDocument, options); + } +export type UpdateCashfreePaymentProviderMutationHookResult = ReturnType; +export type UpdateCashfreePaymentProviderMutationResult = Apollo.MutationResult; +export type UpdateCashfreePaymentProviderMutationOptions = Apollo.BaseMutationOptions; export const UpdateGocardlessPaymentProviderDocument = gql` mutation updateGocardlessPaymentProvider($input: UpdateGocardlessPaymentProviderInput!) { updateGocardlessPaymentProvider(input: $input) { @@ -15929,6 +16247,9 @@ export const GetProviderByCodeForGocardlessDocument = gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on AdyenProvider { id } @@ -16181,6 +16502,9 @@ export const GetProviderByCodeForStripeDocument = gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on AdyenProvider { id } @@ -16857,6 +17181,39 @@ export function useDestroyNangoIntegrationMutation(baseOptions?: Apollo.Mutation export type DestroyNangoIntegrationMutationHookResult = ReturnType; export type DestroyNangoIntegrationMutationResult = Apollo.MutationResult; export type DestroyNangoIntegrationMutationOptions = Apollo.BaseMutationOptions; +export const DeleteCashfreeDocument = gql` + mutation deleteCashfree($input: DestroyPaymentProviderInput!) { + destroyPaymentProvider(input: $input) { + id + } +} + `; +export type DeleteCashfreeMutationFn = Apollo.MutationFunction; + +/** + * __useDeleteCashfreeMutation__ + * + * To run a mutation, you first call `useDeleteCashfreeMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteCashfreeMutation` 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 [deleteCashfreeMutation, { data, loading, error }] = useDeleteCashfreeMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useDeleteCashfreeMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteCashfreeDocument, options); + } +export type DeleteCashfreeMutationHookResult = ReturnType; +export type DeleteCashfreeMutationResult = Apollo.MutationResult; +export type DeleteCashfreeMutationOptions = Apollo.BaseMutationOptions; export const DeleteGocardlessDocument = gql` mutation deleteGocardless($input: DestroyPaymentProviderInput!) { destroyPaymentProvider(input: $input) { @@ -22620,6 +22977,112 @@ export type GetOktaIntegrationQueryHookResult = ReturnType; export type GetOktaIntegrationSuspenseQueryHookResult = ReturnType; export type GetOktaIntegrationQueryResult = Apollo.QueryResult; +export const GetCashfreeIntegrationsDetailsDocument = gql` + query getCashfreeIntegrationsDetails($id: ID!, $limit: Int, $type: ProviderTypeEnum) { + paymentProvider(id: $id) { + ... on CashfreeProvider { + id + ...CashfreeIntegrationDetails + ...DeleteCashfreeIntegrationDialog + ...AddCashfreeProviderDialog + } + } + paymentProviders(limit: $limit, type: $type) { + collection { + ... on CashfreeProvider { + id + } + } + } +} + ${CashfreeIntegrationDetailsFragmentDoc} +${DeleteCashfreeIntegrationDialogFragmentDoc} +${AddCashfreeProviderDialogFragmentDoc}`; + +/** + * __useGetCashfreeIntegrationsDetailsQuery__ + * + * To run a query within a React component, call `useGetCashfreeIntegrationsDetailsQuery` and pass it any options that fit your needs. + * When your component renders, `useGetCashfreeIntegrationsDetailsQuery` 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 } = useGetCashfreeIntegrationsDetailsQuery({ + * variables: { + * id: // value for 'id' + * limit: // value for 'limit' + * type: // value for 'type' + * }, + * }); + */ +export function useGetCashfreeIntegrationsDetailsQuery(baseOptions: Apollo.QueryHookOptions & ({ variables: GetCashfreeIntegrationsDetailsQueryVariables; skip?: boolean; } | { skip: boolean; }) ) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetCashfreeIntegrationsDetailsDocument, options); + } +export function useGetCashfreeIntegrationsDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetCashfreeIntegrationsDetailsDocument, options); + } +export function useGetCashfreeIntegrationsDetailsSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(GetCashfreeIntegrationsDetailsDocument, options); + } +export type GetCashfreeIntegrationsDetailsQueryHookResult = ReturnType; +export type GetCashfreeIntegrationsDetailsLazyQueryHookResult = ReturnType; +export type GetCashfreeIntegrationsDetailsSuspenseQueryHookResult = ReturnType; +export type GetCashfreeIntegrationsDetailsQueryResult = Apollo.QueryResult; +export const GetCashfreeIntegrationsListDocument = gql` + query getCashfreeIntegrationsList($limit: Int, $type: ProviderTypeEnum) { + paymentProviders(limit: $limit, type: $type) { + collection { + ... on CashfreeProvider { + id + ...CashfreeIntegrations + ...AddCashfreeProviderDialog + ...DeleteCashfreeIntegrationDialog + } + } + } +} + ${CashfreeIntegrationsFragmentDoc} +${AddCashfreeProviderDialogFragmentDoc} +${DeleteCashfreeIntegrationDialogFragmentDoc}`; + +/** + * __useGetCashfreeIntegrationsListQuery__ + * + * To run a query within a React component, call `useGetCashfreeIntegrationsListQuery` and pass it any options that fit your needs. + * When your component renders, `useGetCashfreeIntegrationsListQuery` 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 } = useGetCashfreeIntegrationsListQuery({ + * variables: { + * limit: // value for 'limit' + * type: // value for 'type' + * }, + * }); + */ +export function useGetCashfreeIntegrationsListQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetCashfreeIntegrationsListDocument, options); + } +export function useGetCashfreeIntegrationsListLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetCashfreeIntegrationsListDocument, options); + } +export function useGetCashfreeIntegrationsListSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(GetCashfreeIntegrationsListDocument, options); + } +export type GetCashfreeIntegrationsListQueryHookResult = ReturnType; +export type GetCashfreeIntegrationsListLazyQueryHookResult = ReturnType; +export type GetCashfreeIntegrationsListSuspenseQueryHookResult = ReturnType; +export type GetCashfreeIntegrationsListQueryResult = Apollo.QueryResult; export const CreateDunningCampaignDocument = gql` mutation CreateDunningCampaign($input: CreateDunningCampaignInput!) { createDunningCampaign(input: $input) { diff --git a/src/pages/settings/CashfreeIntegrationDetails.tsx b/src/pages/settings/CashfreeIntegrationDetails.tsx new file mode 100644 index 000000000..14ed41d7b --- /dev/null +++ b/src/pages/settings/CashfreeIntegrationDetails.tsx @@ -0,0 +1,475 @@ +import { gql } from '@apollo/client' +import { Stack } from '@mui/material' +import { useMemo, useRef } from 'react' +import { useNavigate, useParams } from 'react-router-dom' + +import { + Avatar, + Button, + ButtonLink, + Chip, + Icon, + Popper, + Skeleton, + Tooltip, + Typography, +} from '~/components/designSystem' +import { + AddCashfreeDialog, + AddCashfreeDialogRef, +} from '~/components/settings/integrations/AddCashfreeDialog' +import { + AddEditDeleteSuccessRedirectUrlDialog, + AddEditDeleteSuccessRedirectUrlDialogRef, +} from '~/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog' +import { + DeleteCashfreeIntegrationDialog, + DeleteCashfreeIntegrationDialogRef, +} from '~/components/settings/integrations/DeleteCashfreeIntegrationDialog' +import { addToast, envGlobalVar, getItemFromLS, ORGANIZATION_LS_KEY_ID } from '~/core/apolloClient' +import { CASHFREE_INTEGRATION_ROUTE, INTEGRATIONS_ROUTE } from '~/core/router' +import { copyToClipboard } from '~/core/utils/copyToClipboard' +import { + AddCashfreeProviderDialogFragmentDoc, + CashfreeIntegrationDetailsFragment, + DeleteCashfreeIntegrationDialogFragmentDoc, + ProviderTypeEnum, + useGetCashfreeIntegrationsDetailsQuery, +} from '~/generated/graphql' +import { useInternationalization } from '~/hooks/core/useInternationalization' +import { usePermissions } from '~/hooks/usePermissions' +import Cashfree from '~/public/images/cashfree.svg' +import { MenuPopper, PageHeader, PopperOpener } from '~/styles' + +const PROVIDER_CONNECTION_LIMIT = 2 + +gql` + fragment CashfreeIntegrationDetails on CashfreeProvider { + id + code + name + clientId + clientSecret + successRedirectUrl + } + + query getCashfreeIntegrationsDetails($id: ID!, $limit: Int, $type: ProviderTypeEnum) { + paymentProvider(id: $id) { + ... on CashfreeProvider { + id + ...CashfreeIntegrationDetails + ...DeleteCashfreeIntegrationDialog + ...AddCashfreeProviderDialog + } + } + + paymentProviders(limit: $limit, type: $type) { + collection { + ... on CashfreeProvider { + id + } + } + } + } + + ${DeleteCashfreeIntegrationDialogFragmentDoc} + ${AddCashfreeProviderDialogFragmentDoc} +` + +const CashfreeIntegrationDetails = () => { + const navigate = useNavigate() + const { integrationId } = useParams() + const { hasPermissions } = usePermissions() + const addDialogRef = useRef(null) + const deleteDialogRef = useRef(null) + const successRedirectUrlDialogRef = useRef(null) + const { apiUrl } = envGlobalVar() + const currentOrganizationId = getItemFromLS(ORGANIZATION_LS_KEY_ID) + const { translate } = useInternationalization() + const { data, loading } = useGetCashfreeIntegrationsDetailsQuery({ + variables: { + id: integrationId as string, + limit: PROVIDER_CONNECTION_LIMIT, + type: ProviderTypeEnum.Cashfree, + }, + skip: !integrationId, + }) + const cashfreePaymentProvider = data?.paymentProvider as CashfreeIntegrationDetailsFragment + const deleteDialogCallback = () => { + if ((data?.paymentProviders?.collection.length || 0) >= PROVIDER_CONNECTION_LIMIT) { + navigate(CASHFREE_INTEGRATION_ROUTE) + } else { + navigate(INTEGRATIONS_ROUTE) + } + } + + const canEditIntegration = hasPermissions(['organizationIntegrationsUpdate']) + const canDeleteIntegration = hasPermissions(['organizationIntegrationsDelete']) + + const webhookUrl = useMemo( + () => + `${apiUrl}/webhooks/cashfree/${currentOrganizationId}?code=${cashfreePaymentProvider?.code}`, + [apiUrl, currentOrganizationId, cashfreePaymentProvider?.code], + ) + + return ( +
+ +
+ + {loading ? ( + + ) : ( + + {cashfreePaymentProvider?.name} + + )} +
+ {(canEditIntegration || canDeleteIntegration) && ( + {translate('text_626162c62f790600f850b6fe')} + } + > + {({ closePopper }) => ( + + {canEditIntegration && ( + <> + + + )} + + {canDeleteIntegration && ( + + )} + + )} + + )} +
+
+ {loading ? ( + <> + +
+ + +
+ + ) : ( + <> + + + +
+
+ + {cashfreePaymentProvider?.name} + + +
+ + {translate('text_1727619878796wmgcntkfycn')} •  + {translate('text_62b1edddbf5f461ab971271f')} + +
+ + )} +
+ +
+
+
+ + {translate('text_664c732c264d7eed1c74fdc5')} + + + {canEditIntegration && ( + + )} +
+ {loading ? ( + <> + {[0, 1, 2].map((i) => ( +
+ + +
+ ))} +
+ + + ) : ( + <> +
+ + + + + + {translate('text_626162c62f790600f850b76a')} + + + {cashfreePaymentProvider.name} + + +
+ +
+ + + + + + {translate('text_62876e85e32e0300e1803127')}{' '} + + + {cashfreePaymentProvider.code} + + +
+ +
+ + + + + + + {translate('text_1727620558031ftsky1vpr55')} + + + {cashfreePaymentProvider.clientId} + + + +
+ +
+ + + + + + + {translate('text_1727620574228qfyoqtsdih7')} + + + {cashfreePaymentProvider.clientSecret} + + + +
+ +
+ + + + + + + {translate('text_6271200984178801ba8bdf22')} + + + {webhookUrl} + + + + + + +
+ + )} + {!loading && ( + + )} +
+ +
+
+ {translate('text_65367cb78324b77fcb6af21c')} + + {canEditIntegration && ( + + )} +
+ + {loading ? ( +
+ + +
+ ) : ( + <> + {!cashfreePaymentProvider?.successRedirectUrl ? ( + + {translate('text_65367cb78324b77fcb6af226', { + connectionName: translate('text_1727619878796wmgcntkfycn'), + })} + + ) : ( +
+
+ + + +
+ + {translate('text_65367cb78324b77fcb6af1c6')} + + + {cashfreePaymentProvider?.successRedirectUrl} + +
+
+
+ {(canEditIntegration || canDeleteIntegration) && ( + ( + // right-0 used to align the popper to the right + + + + )} + + {canDeleteIntegration && ( + + )} + + )} + + )} +
+ )} + + )} +
+
+ + + + +
+ ) +} + +export default CashfreeIntegrationDetails diff --git a/src/pages/settings/CashfreeIntegrations.tsx b/src/pages/settings/CashfreeIntegrations.tsx new file mode 100644 index 000000000..80dad24b2 --- /dev/null +++ b/src/pages/settings/CashfreeIntegrations.tsx @@ -0,0 +1,262 @@ +import { gql } from '@apollo/client' +import { useRef } from 'react' +import { generatePath, useNavigate } from 'react-router-dom' + +import { + Avatar, + Button, + ButtonLink, + Chip, + Icon, + Popper, + Skeleton, + Tooltip, + Typography, +} from '~/components/designSystem' +import { + AddCashfreeDialog, + AddCashfreeDialogRef, +} from '~/components/settings/integrations/AddCashfreeDialog' +import { + AddEditDeleteSuccessRedirectUrlDialog, + AddEditDeleteSuccessRedirectUrlDialogRef, +} from '~/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog' +import { + DeleteCashfreeIntegrationDialog, + DeleteCashfreeIntegrationDialogRef, +} from '~/components/settings/integrations/DeleteCashfreeIntegrationDialog' +import { CASHFREE_INTEGRATION_DETAILS_ROUTE, INTEGRATIONS_ROUTE } from '~/core/router' +import { + AddCashfreeProviderDialogFragmentDoc, + CashfreeForCreateAndEditSuccessRedirectUrlFragmentDoc, + CashfreeProvider, + DeleteCashfreeIntegrationDialogFragmentDoc, + ProviderTypeEnum, + useGetCashfreeIntegrationsListQuery, +} from '~/generated/graphql' +import { useInternationalization } from '~/hooks/core/useInternationalization' +import { usePermissions } from '~/hooks/usePermissions' +import Cashfree from '~/public/images/cashfree.svg' +import { ListItemLink, MenuPopper, PageHeader, PopperOpener } from '~/styles' + +gql` + fragment CashfreeIntegrations on CashfreeProvider { + id + name + code + } + + query getCashfreeIntegrationsList($limit: Int, $type: ProviderTypeEnum) { + paymentProviders(limit: $limit, type: $type) { + collection { + ... on CashfreeProvider { + id + ...CashfreeIntegrations + ...AddCashfreeProviderDialog + ...DeleteCashfreeIntegrationDialog + } + } + } + } + ${CashfreeForCreateAndEditSuccessRedirectUrlFragmentDoc} + ${DeleteCashfreeIntegrationDialogFragmentDoc} + ${AddCashfreeProviderDialogFragmentDoc} +` + +const CashfreeIntegrations = () => { + const navigate = useNavigate() + const { hasPermissions } = usePermissions() + const addCashfreeDialogRef = useRef(null) + const deleteDialogRef = useRef(null) + const successRedirectUrlDialogRef = useRef(null) + const { translate } = useInternationalization() + const { data, loading } = useGetCashfreeIntegrationsListQuery({ + variables: { limit: 1000, type: ProviderTypeEnum.Cashfree }, + }) + const connections = data?.paymentProviders?.collection as CashfreeProvider[] | undefined + const deleteDialogCallback = + connections && connections.length === 1 ? () => navigate(INTEGRATIONS_ROUTE) : undefined + + const canCreateIntegration = hasPermissions(['organizationIntegrationsCreate']) + const canEditIntegration = hasPermissions(['organizationIntegrationsUpdate']) + const canDeleteIntegration = hasPermissions(['organizationIntegrationsDelete']) + + return ( + <> + +
+ + {loading ? ( + + ) : ( + + {translate('text_1727619878796wmgcntkfycn')} + + )} +
+ + {canCreateIntegration && ( + + )} +
+
+ {loading ? ( + <> + +
+ + +
+ + ) : ( + <> + + + +
+ + {translate('text_1727619878796wmgcntkfycn')} + + +
+ {translate('text_62b1edddbf5f461ab971271f')} + + )} +
+ +
+
+ + {translate('text_65846763e6140b469140e239')} + + + <> + {loading ? ( + <> + {[1, 2].map((i) => ( +
+ + +
+ ))} + + ) : ( + <> + {connections?.map((connection, index) => { + return ( +
+ +
+ + + +
+ + {connection.name} + + + {connection.code} + +
+
+
+ + {(canEditIntegration || canDeleteIntegration) && ( + ( + // right-0 used to align the popper to the right + + + + )} + + {canDeleteIntegration && ( + + )} + + )} + + )} +
+ ) + })} + + )} + +
+
+ + + + + + ) +} + +export default CashfreeIntegrations diff --git a/src/pages/settings/Integrations.tsx b/src/pages/settings/Integrations.tsx index 8b459c8b3..494300c93 100644 --- a/src/pages/settings/Integrations.tsx +++ b/src/pages/settings/Integrations.tsx @@ -20,6 +20,10 @@ import { AddAnrokDialog, AddAnrokDialogRef, } from '~/components/settings/integrations/AddAnrokDialog' +import { + AddCashfreeDialog, + AddCashfreeDialogRef, +} from '~/components/settings/integrations/AddCashfreeDialog' import { AddGocardlessDialog, AddGocardlessDialogRef, @@ -50,6 +54,7 @@ import { import { ADYEN_INTEGRATION_ROUTE, ANROK_INTEGRATION_ROUTE, + CASHFREE_INTEGRATION_ROUTE, GOCARDLESS_INTEGRATION_ROUTE, HUBSPOT_INTEGRATION_ROUTE, NETSUITE_INTEGRATION_ROUTE, @@ -65,6 +70,7 @@ import { useOrganizationInfos } from '~/hooks/useOrganizationInfos' import Adyen from '~/public/images/adyen.svg' import Airbyte from '~/public/images/airbyte.svg' import Anrok from '~/public/images/anrok.svg' +import Cashfree from '~/public/images/cashfree.svg' import GoCardless from '~/public/images/gocardless.svg' import HightTouch from '~/public/images/hightouch.svg' import Hubspot from '~/public/images/hubspot.svg' @@ -128,6 +134,7 @@ const Integrations = () => { const addStripeDialogRef = useRef(null) const addAdyenDialogRef = useRef(null) const addGocardlessDialogRef = useRef(null) + const addCashfreeDialogRef = useRef(null) const addLagoTaxManagementDialog = useRef(null) const addNetsuiteDialogRef = useRef(null) const addXeroDialogRef = useRef(null) @@ -147,6 +154,9 @@ const Integrations = () => { const hasGocardlessIntegration = data?.paymentProviders?.collection?.some( (provider) => provider?.__typename === 'GocardlessProvider', ) + const hasCashfreeIntegration = data?.paymentProviders?.collection?.some( + (provider) => provider?.__typename === 'CashfreeProvider', + ) const hasTaxManagement = !!organization?.euTaxManagement const hasAccessToNetsuitePremiumIntegration = !!premiumIntegrations?.includes( PremiumIntegrationTypeEnum.Netsuite, @@ -247,6 +257,28 @@ const Integrations = () => { }} fullWidth /> + + + + } + endIcon={ + hasCashfreeIntegration ? ( + + ) : undefined + } + onClick={() => { + if (hasCashfreeIntegration) { + navigate(CASHFREE_INTEGRATION_ROUTE) + } else { + addCashfreeDialogRef.current?.openDialog() + } + }} + fullWidth + /> { + + + + + diff --git a/translations/base.json b/translations/base.json index 97da99149..1c4847a7c 100644 --- a/translations/base.json +++ b/translations/base.json @@ -2572,5 +2572,20 @@ "text_1729084495407pcn1mei0hyd": "Refunding this prepaid invoice will void automatically the wallet credits once the credit note refund status is marked as succeeded.", "text_1729262241097k3cnpci6p5j": "Prepaid credits", "text_1729262339446mk289ygp31g": "Refund customer", - "text_17295725378539prq3x0wpry": "{{invoiceNumber}} for a remaining subtotal of {{subtotal}}" + "text_17295725378539prq3x0wpry": "{{invoiceNumber}} for a remaining subtotal of {{subtotal}}", + "text_172450747075633492aqpbm2": "Connect to Cashfree Payments", + "text_17245079170372xxmw737fhf": "To connect to Cashfree Payments, please enter the following information.", + "text_1724507963056bu20ky8z98g": "Edit information linked to this Cashfree Payments connection.", + "text_1727619878796wmgcntkfycn": "Cashfree Payments", + "text_1727620558031ftsky1vpr55": "Client id", + "text_1727620574228qfyoqtsdih7": "Client secret", + "text_1727621816788cygs13tsdyv": "By deleting the connection, it will not be used anymore and upcoming data will not be synchronized to the connected Cashfree Payments account. Are you sure?", + "text_17276219350329d36mgsotee": "Cashfree Payments connection successfully created", + "text_1727621947600tg14usmdbb0": "Cashfree Payments connection successfully edited", + "text_1727621949511zk6kkl99pzk": "Cashfree Payments connection successfully deleted", + "text_1727623090069kyp9o88hpqe": "Webhook URL copied to clipboard", + "text_1727623127072q52kj0u3xql": "Copy Webhook URL", + "text_1727623232636ys8hnp8a3su": "Add the following Webhook URL in the Webhooks > Payment Link section of the Cashfree Payments dashboard.", + "text_1727624537843s2ublm4rsyj": "Type a client id", + "text_17276245391922l9540z7f78": "Type a client secret" }