Skip to content

Commit

Permalink
Add Cashfree Payment Provider
Browse files Browse the repository at this point in the history
  • Loading branch information
AyushChothe committed Sep 6, 2024
1 parent 599cffe commit a5a2186
Show file tree
Hide file tree
Showing 16 changed files with 1,884 additions and 17 deletions.
6 changes: 6 additions & 0 deletions src/components/customers/CustomerMainInfos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ gql`
code
}
... on CashfreeProvider {
id
name
code
}
... on AdyenProvider {
id
name
Expand Down
7 changes: 7 additions & 0 deletions src/components/customers/addDrawer/ExternalAppsAccordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ gql`
code
}
... on CashfreeProvider {
__typename
id
name
code
}
... on AdyenProvider {
__typename
id
Expand Down
3 changes: 3 additions & 0 deletions src/components/settings/integrations/AddAdyenDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ gql`
... on GocardlessProvider {
id
}
... on CashfreeProvider {
id
}
... on StripeProvider {
id
}
Expand Down
302 changes: 302 additions & 0 deletions src/components/settings/integrations/AddCashfreeDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
import { gql } from '@apollo/client'
import { Stack } from '@mui/material'
import { useFormik } from 'formik'
import { forwardRef, RefObject, useImperativeHandle, useRef, useState } from 'react'
import { useNavigate } from 'react-router'
import { generatePath } from 'react-router-dom'
import styled from 'styled-components'
import { object, string } from 'yup'

import { Button, Dialog, DialogRef } from '~/components/designSystem'
import { TextInputField } from '~/components/form'
import { addToast } from '~/core/apolloClient'
import { CASHFREE_INTEGRATION_DETAILS_ROUTE } from '~/core/router'
import {
AddCashfreePaymentProviderInput,
AddCashfreeProviderDialogFragment,
CashfreeIntegrationDetailsFragmentDoc,
LagoApiError,
useAddCashfreeApiKeyMutation,
useGetProviderByCodeForCashfreeLazyQuery,
useUpdateCashfreeApiKeyMutation,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'
import { theme } from '~/styles'

import { DeleteCashfreeIntegrationDialogRef } from './DeleteCashfreeIntegrationDialog'

gql`
fragment AddCashfreeProviderDialog on CashfreeProvider {
id
name
code
clientId
clientSecret
}
query getProviderByCodeForCashfree($code: String) {
paymentProvider(code: $code) {
... on CashfreeProvider {
id
}
... on GocardlessProvider {
id
}
... on AdyenProvider {
id
}
... on StripeProvider {
id
}
}
}
mutation addCashfreeApiKey($input: AddCashfreePaymentProviderInput!) {
addCashfreePaymentProvider(input: $input) {
id
...AddCashfreeProviderDialog
...CashfreeIntegrationDetails
}
}
mutation updateCashfreeApiKey($input: UpdateCashfreePaymentProviderInput!) {
updateCashfreePaymentProvider(input: $input) {
id
...AddCashfreeProviderDialog
...CashfreeIntegrationDetails
}
}
${CashfreeIntegrationDetailsFragmentDoc}
`

type TAddCashfreeDialogProps = Partial<{
deleteModalRef: RefObject<DeleteCashfreeIntegrationDialogRef>
provider: AddCashfreeProviderDialogFragment
deleteDialogCallback: Function
}>

export interface AddCashfreeDialogRef {
openDialog: (props?: TAddCashfreeDialogProps) => unknown
closeDialog: () => unknown
}

export const AddCashfreeDialog = forwardRef<AddCashfreeDialogRef>((_, ref) => {
const navigate = useNavigate()
const dialogRef = useRef<DialogRef>(null)

const { translate } = useInternationalization()
const [localData, setLocalData] = useState<TAddCashfreeDialogProps | undefined>(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('Add cashfree success toast'),
severity: 'success',
})
}
},
})

const [updateApiKey] = useUpdateCashfreeApiKeyMutation({
onCompleted({ updateCashfreePaymentProvider }) {
if (updateCashfreePaymentProvider?.id) {
navigate(
generatePath(CASHFREE_INTEGRATION_DETAILS_ROUTE, {
integrationId: updateCashfreePaymentProvider.id,
}),
)

addToast({
message: translate('Edit cashfree success toast'),
severity: 'success',
})
}
},
})

const [getCashfreeProviderByCode] = useGetProviderByCodeForCashfreeLazyQuery()

const formikProps = useFormik<AddCashfreePaymentProviderInput>({
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 (
<Dialog
ref={dialogRef}
title={translate(
isEdition ? 'text_658461066530343fe1808cd9' : 'text_172450747075633492aqpbm2',
{
name: cashfreeProvider?.name,
},
)}
description={translate(
isEdition ? 'text_1724507963056bu20ky8z98g' : 'text_17245079170372xxmw737fhf',
)}
onClose={() => {
formikProps.resetForm()
}}
actions={({ closeDialog }) => (
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
width={isEdition ? '100%' : 'inherit'}
spacing={3}
>
{isEdition && (
<Button
danger
variant="quaternary"
onClick={() => {
closeDialog()
localData?.deleteModalRef?.current?.openDialog({
provider: cashfreeProvider,
callback: localData?.deleteDialogCallback,
})
}}
>
{translate('text_65845f35d7d69c3ab4793dad')}
</Button>
)}
<Stack direction="row" spacing={3} alignItems="center">
<Button variant="quaternary" onClick={closeDialog}>
{translate('text_62b1edddbf5f461ab971276d')}
</Button>
<Button
variant="primary"
disabled={!formikProps.isValid || !formikProps.dirty}
onClick={formikProps.submitForm}
>
{translate(
isEdition ? 'text_65845f35d7d69c3ab4793dac' : 'text_658466afe6140b469140e207',
)}
</Button>
</Stack>
</Stack>
)}
>
<Content>
<InlineInputs>
<TextInputField
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
formikProps={formikProps}
name="name"
label={translate('text_6584550dc4cec7adf861504d')}
placeholder={translate('text_6584550dc4cec7adf861504f')}
/>
<TextInputField
formikProps={formikProps}
name="code"
label={translate('text_6584550dc4cec7adf8615051')}
placeholder={translate('text_6584550dc4cec7adf8615053')}
/>
</InlineInputs>
<InlineInputs>
<TextInputField
formikProps={formikProps}
disabled={isEdition}
name="clientId"
label={'clientId'}
placeholder={translate('text_6584550dc4cec7adf8615053')}
/>
<TextInputField
formikProps={formikProps}
disabled={isEdition}
name="clientSecret"
label={'clientSecret'}
placeholder={translate('text_6584550dc4cec7adf8615053')}
/>
</InlineInputs>
</Content>
</Dialog>
)
})

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'
Loading

0 comments on commit a5a2186

Please sign in to comment.