Skip to content

Commit

Permalink
feat: display record payment CTA
Browse files Browse the repository at this point in the history
  • Loading branch information
keellyp committed Jan 28, 2025
1 parent 58ca739 commit 564d249
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 28 deletions.
36 changes: 35 additions & 1 deletion src/components/customers/CustomerInvoicesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { CustomerInvoiceDetailsTabsOptionsEnum } from '~/core/constants/Navigati
import { invoiceStatusMapping, paymentStatusMapping } from '~/core/constants/statusInvoiceMapping'
import { intlFormatNumber } from '~/core/formats/intlFormatNumber'
import {
CREATE_INVOICE_PAYMENT_ROUTE,
CUSTOMER_INVOICE_CREATE_CREDIT_NOTE_ROUTE,
CUSTOMER_INVOICE_DETAILS_ROUTE,
} from '~/core/router'
Expand All @@ -24,6 +25,7 @@ import {
InvoiceStatusTypeEnum,
InvoiceTaxStatusTypeEnum,
LagoApiError,
PremiumIntegrationTypeEnum,
TimezoneEnum,
useDownloadInvoiceItemMutation,
useRetryInvoicePaymentMutation,
Expand All @@ -32,6 +34,7 @@ import { useInternationalization } from '~/hooks/core/useInternationalization'
import { useCurrentUser } from '~/hooks/useCurrentUser'
import { usePermissions } from '~/hooks/usePermissions'

import { useOrganizationInfos } from '../../hooks/useOrganizationInfos'
import { createCreditNoteForInvoiceButtonProps } from '../creditNote/utils'
import {
UpdateInvoicePaymentStatusDialog,
Expand All @@ -51,6 +54,7 @@ gql`
number
issuingDate
totalAmountCents
totalDueAmountCents
currency
voidable
paymentDisputeLostAt
Expand Down Expand Up @@ -131,6 +135,8 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
const { isPremium } = useCurrentUser()
const { translate } = useInternationalization()
const { hasPermissions } = usePermissions()
const { organization: { premiumIntegrations } = {} } = useOrganizationInfos()

const premiumWarningDialogRef = useRef<PremiumWarningDialogRef>(null)

const [retryCollect] = useRetryInvoicePaymentMutation({
Expand Down Expand Up @@ -311,7 +317,7 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
},
]}
actionColumn={(invoice) => {
const { status, paymentStatus, voidable, taxStatus } = invoice
const { status, paymentStatus, voidable, taxStatus, totalDueAmountCents } = invoice

const { disabledIssueCreditNoteButton, disabledIssueCreditNoteButtonLabel } =
createCreditNoteForInvoiceButtonProps({
Expand Down Expand Up @@ -357,6 +363,7 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
const canIssueCreditNote =
![InvoiceStatusTypeEnum.Draft, InvoiceStatusTypeEnum.Voided].includes(status) &&
hasPermissions(['creditNotesCreate'])
const canRecordPayment = totalDueAmountCents > 0 && hasPermissions(['paymentsCreate'])

return [
canDownload
Expand Down Expand Up @@ -388,6 +395,33 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
},
},

canRecordPayment
? {
startIcon: 'receipt',
title: translate('text_1737471851634wpeojigr27w'),

endIcon: premiumIntegrations?.includes(
PremiumIntegrationTypeEnum.ManualPayments,
)
? undefined
: 'sparkles',
onAction: ({ id }) => {
if (
premiumIntegrations?.includes(PremiumIntegrationTypeEnum.ManualPayments)
) {
navigate(generatePath(CREATE_INVOICE_PAYMENT_ROUTE, { invoiceId: id }))
} else {
premiumWarningDialogRef.current?.openDialog({
title: translate('text_1738059367337v2tfzq3mr5u'),
description: translate('text_1738059367337mm2dwg2af6g'),
mailtoSubject: translate('text_1738059367337hy6e2c7pa3t'),
mailtoBody: translate('text_1738059367337km2lr0xueue'),
})
}
},
}
: null,

canRetryCollect
? {
startIcon: 'push',
Expand Down
27 changes: 24 additions & 3 deletions src/components/customers/CustomerPaymentsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
import { FC } from 'react'
import { generatePath } from 'react-router-dom'

import { Skeleton, Typography } from '~/components/designSystem'
import { useGetPaymentListQuery } from '~/generated/graphql'
import { ButtonLink, Skeleton, Typography } from '~/components/designSystem'
import { PremiumIntegrationTypeEnum, useGetPaymentListQuery } from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'

import { CustomerPaymentsList } from './CustomerPaymentsList'

import { CREATE_PAYMENT_ROUTE } from '../../core/router'
import { useOrganizationInfos } from '../../hooks/useOrganizationInfos'
import { usePermissions } from '../../hooks/usePermissions'

interface CustomerPaymentsTabProps {
externalCustomerId: string
}

export const CustomerPaymentsTab: FC<CustomerPaymentsTabProps> = ({ externalCustomerId }) => {
const { translate } = useInternationalization()

const { hasPermissions } = usePermissions()
const { organization: { premiumIntegrations } = {} } = useOrganizationInfos()
const { data, loading, fetchMore } = useGetPaymentListQuery({
variables: { externalCustomerId: externalCustomerId as string, limit: 20 },
skip: !externalCustomerId,
})

const payments = data?.payments.collection || []

const canRecordPayment =
hasPermissions(['paymentsCreate']) &&
premiumIntegrations?.includes(PremiumIntegrationTypeEnum.ManualPayments)

return (
<div className="flex flex-col gap-4">
<div className="mt-6 flex items-center justify-between">
Expand All @@ -30,6 +40,17 @@ export const CustomerPaymentsTab: FC<CustomerPaymentsTabProps> = ({ externalCust
<Typography variant="subhead" color="grey700" className="flex-1">
{translate('text_6672ebb8b1b50be550eccbed')}
</Typography>
{canRecordPayment && (
<ButtonLink
type="button"
to={generatePath(CREATE_PAYMENT_ROUTE)}
buttonProps={{
variant: 'quaternary',
}}
>
{translate('text_1737471851634wpeojigr27w')}
</ButtonLink>
)}
</div>
)}
</div>
Expand Down
30 changes: 27 additions & 3 deletions src/components/invoices/InvoicePaymentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@ import { generatePath, useParams } from 'react-router-dom'

import { payablePaymentStatusMapping } from '~/core/constants/statusInvoiceMapping'
import { intlFormatNumber } from '~/core/formats/intlFormatNumber'
import { PAYMENT_DETAILS_ROUTE } from '~/core/router'
import { CREATE_INVOICE_PAYMENT_ROUTE, PAYMENT_DETAILS_ROUTE } from '~/core/router'
import { deserializeAmount } from '~/core/serializers/serializeAmount'
import { formatDateToTZ } from '~/core/timezone'
import { CurrencyEnum, PaymentTypeEnum, useGetPaymentListQuery } from '~/generated/graphql'
import {
CurrencyEnum,
PaymentTypeEnum,
PremiumIntegrationTypeEnum,
useGetPaymentListQuery,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'

import { InfiniteScroll, Status, Table, Typography } from '../designSystem'
import { useOrganizationInfos } from '../../hooks/useOrganizationInfos'
import { usePermissions } from '../../hooks/usePermissions'
import { ButtonLink, InfiniteScroll, Status, Table, Typography } from '../designSystem'
import { PaymentProviderChip } from '../PaymentProviderChip'

export const InvoicePaymentList = () => {
const { translate } = useInternationalization()
const { hasPermissions } = usePermissions()
const { organization: { premiumIntegrations } = {} } = useOrganizationInfos()
const { invoiceId } = useParams()

const { data, loading, error, fetchMore } = useGetPaymentListQuery({
Expand All @@ -22,10 +31,25 @@ export const InvoicePaymentList = () => {

const payments = data?.payments.collection || []

const canRecordPayment =
hasPermissions(['paymentsCreate']) &&
premiumIntegrations?.includes(PremiumIntegrationTypeEnum.ManualPayments)

return (
<>
<div className="flex h-18 items-center justify-between shadow-b">
<Typography variant="subhead">{translate('text_6672ebb8b1b50be550eccbed')}</Typography>
{canRecordPayment && (
<ButtonLink
type="button"
to={generatePath(CREATE_INVOICE_PAYMENT_ROUTE, { invoiceId: invoiceId as string })}
buttonProps={{
variant: 'quaternary',
}}
>
{translate('text_1737471851634wpeojigr27w')}
</ButtonLink>
)}
</div>
{!loading && !payments.length && (
<Typography className="mt-6" variant="body" color="grey500">
Expand Down
34 changes: 33 additions & 1 deletion src/components/invoices/InvoicesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { CustomerInvoiceDetailsTabsOptionsEnum } from '~/core/constants/Navigati
import { invoiceStatusMapping, paymentStatusMapping } from '~/core/constants/statusInvoiceMapping'
import { intlFormatNumber } from '~/core/formats/intlFormatNumber'
import {
CREATE_INVOICE_PAYMENT_ROUTE,
CUSTOMER_INVOICE_CREATE_CREDIT_NOTE_ROUTE,
CUSTOMER_INVOICE_DETAILS_ROUTE,
INVOICE_SETTINGS_ROUTE,
Expand All @@ -31,13 +32,15 @@ import {
InvoicePaymentStatusTypeEnum,
InvoiceStatusTypeEnum,
LagoApiError,
PremiumIntegrationTypeEnum,
useDownloadInvoiceItemMutation,
useRetryInvoicePaymentMutation,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'
import { useCurrentUser } from '~/hooks/useCurrentUser'
import { usePermissions } from '~/hooks/usePermissions'

import { useOrganizationInfos } from '../../hooks/useOrganizationInfos'
import { createCreditNoteForInvoiceButtonProps } from '../creditNote/utils'
import {
AvailableFiltersEnum,
Expand Down Expand Up @@ -74,6 +77,7 @@ const InvoicesList = ({
const { isPremium } = useCurrentUser()
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const { organization: { premiumIntegrations } = {} } = useOrganizationInfos()

const finalizeInvoiceRef = useRef<FinalizeInvoiceDialogRef>(null)
const updateInvoicePaymentStatusDialog = useRef<UpdateInvoicePaymentStatusDialogRef>(null)
Expand Down Expand Up @@ -149,7 +153,7 @@ const InvoicesList = ({
isLoading={isLoading}
hasError={!!error}
actionColumn={(invoice) => {
const { status, paymentStatus, voidable } = invoice
const { status, paymentStatus, voidable, totalDueAmountCents } = invoice

const { disabledIssueCreditNoteButton, disabledIssueCreditNoteButtonLabel } =
createCreditNoteForInvoiceButtonProps({
Expand Down Expand Up @@ -193,6 +197,7 @@ const InvoicesList = ({
const canIssueCreditNote =
![InvoiceStatusTypeEnum.Draft, InvoiceStatusTypeEnum.Voided].includes(status) &&
hasPermissions(['creditNotesCreate'])
const canRecordPayment = totalDueAmountCents > 0 && hasPermissions(['paymentsCreate'])

return [
canDownload
Expand Down Expand Up @@ -224,6 +229,33 @@ const InvoicesList = ({
},
},

canRecordPayment
? {
startIcon: 'receipt',
title: translate('text_1737471851634wpeojigr27w'),

endIcon: premiumIntegrations?.includes(
PremiumIntegrationTypeEnum.ManualPayments,
)
? undefined
: 'sparkles',
onAction: ({ id }) => {
if (
premiumIntegrations?.includes(PremiumIntegrationTypeEnum.ManualPayments)
) {
navigate(generatePath(CREATE_INVOICE_PAYMENT_ROUTE, { invoiceId: id }))
} else {
premiumWarningDialogRef.current?.openDialog({
title: translate('text_1738059367337v2tfzq3mr5u'),
description: translate('text_1738059367337mm2dwg2af6g'),
mailtoSubject: translate('text_1738059367337hy6e2c7pa3t'),
mailtoBody: translate('text_1738059367337km2lr0xueue'),
})
}
},
}
: null,

canRetryCollect
? {
startIcon: 'push',
Expand Down
Loading

0 comments on commit 564d249

Please sign in to comment.