From 9d3125d515b528f4a4332b381953cf76c4c93ca2 Mon Sep 17 00:00:00 2001 From: Ayush Chothe Date: Fri, 6 Sep 2024 23:42:55 +0530 Subject: [PATCH] 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 | 302 ++++++++++ .../AddEditDeleteSuccessRedirectUrlDialog.tsx | 30 + .../integrations/AddGocardlessDialog.tsx | 3 + .../settings/integrations/AddStripeDialog.tsx | 3 + .../DeleteCashfreeIntegrationDialog.tsx | 85 +++ src/core/router/SettingRoutes.tsx | 24 + src/generated/graphql.tsx | 493 +++++++++++++++- .../settings/CashfreeIntegrationDetails.tsx | 553 ++++++++++++++++++ src/pages/settings/CashfreeIntegrations.tsx | 345 +++++++++++ src/pages/settings/Integrations.tsx | 34 +- src/public/images/cashfree.svg | 82 +++ translations/base.json | 17 +- 16 files changed, 1991 insertions(+), 21 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 100755 src/public/images/cashfree.svg diff --git a/src/components/customers/CustomerMainInfos.tsx b/src/components/customers/CustomerMainInfos.tsx index edc406b61..9827fbaae 100644 --- a/src/components/customers/CustomerMainInfos.tsx +++ b/src/components/customers/CustomerMainInfos.tsx @@ -26,6 +26,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 Netsuite from '~/public/images/netsuite.svg' import Stripe from '~/public/images/stripe.svg' @@ -112,6 +113,12 @@ gql` code } + ... on CashfreeProvider { + id + name + code + } + ... on AdyenProvider { id name @@ -385,6 +392,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 095317f4e..2571c4cb7 100644 --- a/src/components/customers/addDrawer/AddCustomerDrawer.tsx +++ b/src/components/customers/addDrawer/AddCustomerDrawer.tsx @@ -40,6 +40,7 @@ import { NetsuiteCustomer, ProviderCustomer, ProviderPaymentMethodsEnum, + ProviderTypeEnum, TimezoneEnum, UpdateCustomerInput, XeroCustomer, @@ -128,9 +129,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 0c5e3d9b7..6cb7cc44e 100644 --- a/src/components/customers/addDrawer/ExternalAppsAccordion.tsx +++ b/src/components/customers/addDrawer/ExternalAppsAccordion.tsx @@ -46,6 +46,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 Netsuite from '~/public/images/netsuite.svg' import PSPIcons from '~/public/images/psp-icons.svg' @@ -95,6 +96,13 @@ gql` code } + ... on CashfreeProvider { + __typename + id + name + code + } + ... on AdyenProvider { __typename id @@ -221,6 +229,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, @@ -387,6 +403,8 @@ export const ExternalAppsAccordion = ({ formikProps, isEdition }: TExternalAppsA ) : formikProps.values.paymentProvider === ProviderTypeEnum?.Adyen ? ( + ) : formikProps.values.paymentProvider === ProviderTypeEnum?.Cashfree ? ( + ) : null} ) : ( @@ -453,7 +471,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 && ( + + )} + + + + + + )} + > + + + + + + + + + + + + ) +}) + +const Content = styled.div` + margin-bottom: ${theme.spacing(8)}; + + > *:not(:last-child) { + margin-bottom: ${theme.spacing(6)}; + } +` + +const InlineInputs = styled.div` + display: flex; + flex-direction: row; + align-items: flex-start; + gap: ${theme.spacing(6)}; + + > * { + flex: 1; + } +` + +AddCashfreeDialog.displayName = 'AddCashfreeDialog' diff --git a/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx b/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx index 2069004d7..a0c002b0a 100644 --- a/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx +++ b/src/components/settings/integrations/AddEditDeleteSuccessRedirectUrlDialog.tsx @@ -10,12 +10,15 @@ 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' @@ -28,6 +31,11 @@ gql` successRedirectUrl } + fragment CashfreeForCreateAndEditSuccessRedirectUrl on CashfreeProvider { + id + successRedirectUrl + } + fragment gocardlessForCreateAndEditSuccessRedirectUrl on GocardlessProvider { id successRedirectUrl @@ -45,6 +53,13 @@ gql` } } + mutation updateCashfreePaymentProvider($input: UpdateCashfreePaymentProviderInput!) { + updateCashfreePaymentProvider(input: $input) { + id + successRedirectUrl + } + } + mutation updateGocardlessPaymentProvider($input: UpdateGocardlessPaymentProviderInput!) { updateGocardlessPaymentProvider(input: $input) { id @@ -70,6 +85,7 @@ const AddEditDeleteSuccessRedirectUrlDialogProviderType = { Adyen: 'Adyen', Stripe: 'Stripe', GoCardless: 'GoCardless', + Cashfree: 'Cashfree', } as const type LocalProviderType = { @@ -77,6 +93,7 @@ type LocalProviderType = { type: keyof typeof AddEditDeleteSuccessRedirectUrlDialogProviderType provider?: | AdyenForCreateAndEditSuccessRedirectUrlFragment + | CashfreeForCreateAndEditSuccessRedirectUrlFragment | GocardlessForCreateAndEditSuccessRedirectUrlFragment | StripeForCreateAndEditSuccessRedirectUrlFragment | null @@ -110,6 +127,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 +162,7 @@ export const AddEditDeleteSuccessRedirectUrlDialog = const formikProps = useFormik< | UpdateAdyenPaymentProviderInput + | UpdateCashfreePaymentProviderInput | UpdateGocardlessPaymentProviderInput | UpdateStripePaymentProviderInput >({ @@ -151,6 +180,7 @@ export const AddEditDeleteSuccessRedirectUrlDialog = [AddEditDeleteSuccessRedirectUrlDialogProviderType.Adyen]: updateAdyenProvider, [AddEditDeleteSuccessRedirectUrlDialogProviderType.Stripe]: updateStripeProvider, [AddEditDeleteSuccessRedirectUrlDialogProviderType.GoCardless]: updateGocardlessProvider, + [AddEditDeleteSuccessRedirectUrlDialogProviderType.Cashfree]: updateCashfreeProvider, } const method = methodLoojup[localData?.type as LocalProviderType['type']] diff --git a/src/components/settings/integrations/AddGocardlessDialog.tsx b/src/components/settings/integrations/AddGocardlessDialog.tsx index a7c52aee6..9350d45f2 100644 --- a/src/components/settings/integrations/AddGocardlessDialog.tsx +++ b/src/components/settings/integrations/AddGocardlessDialog.tsx @@ -36,6 +36,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 bf1a2efdc..d639ee99a 100644 --- a/src/core/router/SettingRoutes.tsx +++ b/src/core/router/SettingRoutes.tsx @@ -64,6 +64,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( @@ -121,6 +131,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` @@ -238,6 +250,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 b1b454f36..1a795e804 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; @@ -879,7 +900,7 @@ export enum CountryCode { Tn = 'TN', /** Tonga */ To = 'TO', - /** Turkey */ + /** Türkiye */ Tr = 'TR', /** Trinidad and Tobago */ Tt = 'TT', @@ -1701,6 +1722,7 @@ export type CurrentOrganization = { adyenPaymentProviders?: Maybe>; apiKey?: Maybe; billingConfiguration?: Maybe; + cashfreePaymentProviders?: Maybe>; city?: Maybe; country?: Maybe; createdAt: Scalars['ISO8601DateTime']['output']; @@ -2868,6 +2890,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 */ @@ -3020,6 +3044,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 */ @@ -3077,6 +3103,11 @@ export type MutationAddAdyenPaymentProviderArgs = { }; +export type MutationAddCashfreePaymentProviderArgs = { + input: AddCashfreePaymentProviderInput; +}; + + export type MutationAddGocardlessPaymentProviderArgs = { input: AddGocardlessPaymentProviderInput; }; @@ -3462,6 +3493,11 @@ export type MutationUpdateBillableMetricArgs = { }; +export type MutationUpdateCashfreePaymentProviderArgs = { + input: UpdateCashfreePaymentProviderInput; +}; + + export type MutationUpdateCouponArgs = { input: UpdateCouponInput; }; @@ -3679,7 +3715,7 @@ export type OverdueBalanceCollection = { metadata: CollectionMetadata; }; -export type PaymentProvider = AdyenProvider | GocardlessProvider | StripeProvider; +export type PaymentProvider = AdyenProvider | CashfreeProvider | GocardlessProvider | StripeProvider; /** PaymentProviderCollection type */ export type PaymentProviderCollection = { @@ -3918,6 +3954,7 @@ export enum ProviderPaymentMethodsEnum { export enum ProviderTypeEnum { Adyen = 'adyen', + Cashfree = 'cashfree', Gocardless = 'gocardless', Stripe = 'stripe' } @@ -4575,7 +4612,7 @@ export type SubscriptionLifetimeUsage = { __typename?: 'SubscriptionLifetimeUsage'; lastThresholdAmountCents?: Maybe; nextThresholdAmountCents?: Maybe; - nextTresholdRatio?: Maybe; + nextThresholdRatio?: Maybe; totalUsageAmountCents: Scalars['BigInt']['output']; totalUsageFromDatetime: Scalars['ISO8601DateTime']['output']; totalUsageToDatetime: Scalars['ISO8601DateTime']['output']; @@ -5031,6 +5068,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; @@ -5750,7 +5797,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; @@ -5858,7 +5905,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; @@ -6416,7 +6463,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; @@ -6448,8 +6495,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 }; @@ -6461,6 +6533,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; }>; @@ -6482,7 +6561,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; @@ -6521,7 +6600,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; @@ -6671,6 +6750,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<{ @@ -7733,7 +7821,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 }; @@ -7743,7 +7831,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 }; @@ -7782,6 +7870,27 @@ export type GetOktaIntegrationQueryVariables = Exact<{ export type GetOktaIntegrationQuery = { __typename?: 'Query', integration?: { __typename?: 'AnrokIntegration' } | { __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 GocardlessIntegrationDetailsFragment = { __typename?: 'GocardlessProvider', id: string, code: string, name: string, successRedirectUrl?: string | null, webhookSecret?: string | null }; export type GetGocardlessIntegrationsDetailsQueryVariables = Exact<{ @@ -7791,7 +7900,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 }; @@ -7810,14 +7919,14 @@ 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 IntegrationsSettingQueryVariables = Exact<{ limit?: InputMaybe; }>; -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?: '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?: 'NetsuiteIntegration', id: string } | { __typename?: 'OktaIntegration' } | { __typename?: 'XeroIntegration', id: string }> } | null }; export type GetOrganizationSettingsQueryVariables = Exact<{ appliedToOrganization?: InputMaybe; @@ -7896,7 +8005,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 }; @@ -7906,7 +8015,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 GetTaxesSettingsInformationsQueryVariables = Exact<{ limit?: InputMaybe; @@ -8601,12 +8710,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 @@ -8712,6 +8836,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 @@ -10420,6 +10550,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 GocardlessIntegrationDetailsFragmentDoc = gql` fragment GocardlessIntegrationDetails on GocardlessProvider { id @@ -11515,6 +11662,11 @@ export const PaymentProvidersListForCustomerMainInfosDocument = gql` name code } + ... on CashfreeProvider { + id + name + code + } ... on AdyenProvider { id name @@ -12029,6 +12181,12 @@ export const PaymentProvidersListForCustomerCreateEditExternalAppsAccordionDocum name code } + ... on CashfreeProvider { + __typename + id + name + code + } ... on AdyenProvider { __typename id @@ -14334,6 +14492,9 @@ export const GetProviderByCodeForAdyenDocument = gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on StripeProvider { id } @@ -14517,6 +14678,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.SuspenseQueryHookOptions) { + const options = {...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) { @@ -14551,6 +14835,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) { @@ -14625,6 +14943,9 @@ export const GetProviderByCodeForGocardlessDocument = gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on AdyenProvider { id } @@ -14811,6 +15132,9 @@ export const GetProviderByCodeForStripeDocument = gql` ... on GocardlessProvider { id } + ... on CashfreeProvider { + id + } ... on AdyenProvider { id } @@ -15487,6 +15811,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) { @@ -20981,6 +21338,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.SuspenseQueryHookOptions) { + const options = {...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.SuspenseQueryHookOptions) { + const options = {...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 GetGocardlessIntegrationsDetailsDocument = gql` query getGocardlessIntegrationsDetails($id: ID!, $limit: Int, $type: ProviderTypeEnum) { paymentProvider(id: $id) { diff --git a/src/pages/settings/CashfreeIntegrationDetails.tsx b/src/pages/settings/CashfreeIntegrationDetails.tsx new file mode 100644 index 000000000..6db26ea8b --- /dev/null +++ b/src/pages/settings/CashfreeIntegrationDetails.tsx @@ -0,0 +1,553 @@ +import { gql } from '@apollo/client' +import { Stack } from '@mui/material' +import { useMemo, useRef } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import styled from 'styled-components' + +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, NAV_HEIGHT, PageHeader, PopperOpener, theme } 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) && ( + ( + + + + )} + + {canDeleteIntegration && ( + + )} + + )} + + )} +
+ )} + + )} +
+
+ + + + +
+ ) +} + +const HeaderBlock = styled.div` + display: flex; + align-items: center; + + > *:first-child  { + margin-right: ${theme.spacing(3)}; + } +` + +const MainInfos = styled.div` + display: flex; + align-items: center; + padding: ${theme.spacing(8)} ${theme.spacing(12)}; + + ${theme.breakpoints.down('md')} { + padding: ${theme.spacing(8)} ${theme.spacing(4)}; + } +` + +const ContentWrapper = styled.div` + max-width: ${theme.spacing(168)}; + padding: 0 ${theme.spacing(12)}; + display: flex; + flex-direction: column; + gap: ${theme.spacing(8)}; + + ${theme.breakpoints.down('md')} { + padding: 0 ${theme.spacing(4)}; + } +` + +const Title = styled(Typography)` + height: ${NAV_HEIGHT}px; + width: 100%; + display: flex; + align-items: center; +` + +const Item = styled(Stack)` + height: ${NAV_HEIGHT}px; + max-width: ${theme.spacing(168)}; + box-shadow: ${theme.shadows[7]}; +` + +const Info = styled(Typography)` + margin-top: ${theme.spacing(3)}; +` + +const StyledAvatar = styled(Avatar)` + margin-right: ${theme.spacing(4)}; +` + +const Line = styled.div` + display: flex; + align-items: center; + + > *:first-child { + margin-right: ${theme.spacing(2)}; + } +` + +const InlineTitle = styled.div` + position: relative; + height: ${NAV_HEIGHT}px; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +` + +const LocalPopper = styled(Popper)` + position: relative; + height: 100%; + > *:first-child { + right: 0; + top: 16px; + } +` + +const SuccessPaumentRedirectUrlItem = styled.div` + height: ${NAV_HEIGHT}px; + box-shadow: ${theme.shadows[7]}; + display: flex; + align-items: center; + justify-content: space-between; +` + +const SuccessPaumentRedirectUrlItemLeft = styled.div` + display: flex; + align-items: center; + gap: ${theme.spacing(3)}; +` + +export default CashfreeIntegrationDetails diff --git a/src/pages/settings/CashfreeIntegrations.tsx b/src/pages/settings/CashfreeIntegrations.tsx new file mode 100644 index 000000000..1f91e7a34 --- /dev/null +++ b/src/pages/settings/CashfreeIntegrations.tsx @@ -0,0 +1,345 @@ +import { gql } from '@apollo/client' +import { Stack } from '@mui/material' +import { useRef } from 'react' +import { generatePath, useNavigate } from 'react-router-dom' +import styled from 'styled-components' + +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 { + ItemContainer, + ListItemLink, + MenuPopper, + NAV_HEIGHT, + PageHeader, + PopperOpener, + theme, +} 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) && ( + ( + + + + )} + + {canDeleteIntegration && ( + + )} + + )} + + )} +
+ ) + })} + + )} + +
+
+ + + + + + ) +} + +const HeaderBlock = styled.div` + display: flex; + align-items: center; + + > *:first-child  { + margin-right: ${theme.spacing(3)}; + } +` + +const MainInfos = styled.div` + display: flex; + align-items: center; + padding: ${theme.spacing(8)} ${theme.spacing(12)}; + + ${theme.breakpoints.down('md')} { + padding: ${theme.spacing(8)} ${theme.spacing(4)}; + } +` + +const ListWrapper = styled.div` + display: flex; + flex-direction: column; + gap: ${theme.spacing(8)}; + padding: 0 ${theme.spacing(12)}; + box-sizing: border-box; + max-width: ${theme.spacing(168)}; + + ${theme.breakpoints.down('md')} { + padding: 0 ${theme.spacing(4)}; + } +` + +const InlineTitle = styled.div` + position: relative; + height: ${NAV_HEIGHT}px; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +` + +const LocalListItemLink = styled(ListItemLink)` + padding: 0; +` + +const ListItem = styled.div` + height: ${NAV_HEIGHT}px; + box-shadow: ${theme.shadows[7]}; + display: flex; + align-items: center; + + > *:first-child { + margin-right: ${theme.spacing(3)}; + } +` + +const StyledAvatar = styled(Avatar)` + margin-right: ${theme.spacing(4)}; +` + +const Line = styled.div` + display: flex; + align-items: center; + + > *:first-child { + margin-right: ${theme.spacing(2)}; + } +` + +const ButtonMock = styled.div` + width: 40px; + min-width: 40px; +` + +const LocalPopperOpener = styled(PopperOpener)` + right: 0; +` + +export default CashfreeIntegrations diff --git a/src/pages/settings/Integrations.tsx b/src/pages/settings/Integrations.tsx index 681b635b1..ff2b3bd8d 100644 --- a/src/pages/settings/Integrations.tsx +++ b/src/pages/settings/Integrations.tsx @@ -13,6 +13,10 @@ import { AddAnrokDialog, AddAnrokDialogRef, } from '~/components/settings/integrations/AddAnrokDialog' +import { + AddCashfreeDialog, + AddCashfreeDialogRef, +} from '~/components/settings/integrations/AddCashfreeDialog' import { AddGocardlessDialog, AddGocardlessDialogRef, @@ -39,6 +43,7 @@ import { import { ADYEN_INTEGRATION_ROUTE, ANROK_INTEGRATION_ROUTE, + CASHFREE_INTEGRATION_ROUTE, GOCARDLESS_INTEGRATION_ROUTE, NETSUITE_INTEGRATION_ROUTE, STRIPE_INTEGRATION_ROUTE, @@ -52,6 +57,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 LagoTaxManagement from '~/public/images/lago-tax-management.svg' @@ -113,6 +119,7 @@ const Integrations = () => { const addStripeDialogRef = useRef(null) const addAdyenDialogRef = useRef(null) const addGocardlessnDialogRef = useRef(null) + const addCashfreeDialogRef = useRef(null) const addLagoTaxManagementDialog = useRef(null) const addNetsuiteDialogRef = useRef(null) const addXeroDialogRef = useRef(null) @@ -130,6 +137,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, @@ -224,7 +234,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 7b8d8f6d8..4fdcdb241 100644 --- a/translations/base.json +++ b/translations/base.json @@ -2381,5 +2381,20 @@ "text_1724346450317iqs2rtvx1tp": "Hello, I would like to access your progressive billing add-on. \n\nPlease let me know if you need more info!", "text_1724936123802q74m2xxak3o": "Usage already billed", "text_17250100329108guatmyl9tj": "Unknown", - "text_172535279177716n7p2svtdb": "Anrok synchronisation successfully triggered." + "text_172535279177716n7p2svtdb": "Anrok synchronisation successfully triggered.", + "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" }