Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

misc: unify coupons experience #1985

Merged
merged 4 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 46 additions & 18 deletions src/components/coupons/DeleteCouponDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { gql } from '@apollo/client'
import { forwardRef, useImperativeHandle, useRef, useState } from 'react'

import { DialogRef, Typography } from '~/components/designSystem'
import { DialogRef, Skeleton, Typography } from '~/components/designSystem'
import { WarningDialog } from '~/components/WarningDialog'
import { addToast } from '~/core/apolloClient'
import { DeleteCouponFragment, useDeleteCouponMutation } from '~/generated/graphql'
import { useDeleteCouponMutation, useGetCouponToDeleteLazyQuery } from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'

gql`
fragment DeleteCoupon on Coupon {
id
name
appliedCouponsCount
}

query getCouponToDelete($id: ID!) {
coupon(id: $id) {
...DeleteCoupon
}
}

mutation deleteCoupon($input: DestroyCouponInput!) {
Expand All @@ -21,20 +28,24 @@ gql`
`

type DeleteCouponDialogProps = {
coupon: DeleteCouponFragment
couponId: string
callback?: () => void
}

export interface DeleteCouponDialogRef {
openDialog: ({ coupon, callback }: DeleteCouponDialogProps) => unknown
openDialog: ({ couponId, callback }: DeleteCouponDialogProps) => unknown
closeDialog: () => unknown
}

export const DeleteCouponDialog = forwardRef<DeleteCouponDialogRef>((_, ref) => {
const { translate } = useInternationalization()
const dialogRef = useRef<DialogRef>(null)
const [localData, setLocalData] = useState<DeleteCouponDialogProps | undefined>(undefined)
const coupon = localData?.coupon
const [getCouponToDelete, { data: couponData, loading: couponLoading }] =
useGetCouponToDeleteLazyQuery({
nextFetchPolicy: 'cache-only',
})
const coupon = couponData?.coupon

const [deleteCoupon] = useDeleteCouponMutation({
onCompleted(data) {
Expand All @@ -47,20 +58,13 @@ export const DeleteCouponDialog = forwardRef<DeleteCouponDialogRef>((_, ref) =>
localData?.callback && localData.callback()
}
},
update(cache, { data }) {
if (!data?.destroyCoupon) return
const cacheId = cache.identify({
id: data?.destroyCoupon.id,
__typename: 'Coupon',
})

cache.evict({ id: cacheId })
},
refetchQueries: ['coupons'],
})

useImperativeHandle(ref, () => ({
openDialog: (data) => {
setLocalData(data)
getCouponToDelete({ variables: { id: data.couponId } })
dialogRef.current?.openDialog()
},
closeDialog: () => dialogRef.current?.closeDialog(),
Expand All @@ -69,10 +73,34 @@ export const DeleteCouponDialog = forwardRef<DeleteCouponDialogRef>((_, ref) =>
return (
<WarningDialog
ref={dialogRef}
title={translate('text_628b432fd8f2bc0105b973ee', {
couponName: coupon?.name,
})}
description={<Typography html={translate('text_628b432fd8f2bc0105b973f6')} />}
title={
couponLoading ? (
<Skeleton className="mb-5 h-4 w-full" variant="text" />
) : (
translate('text_628b432fd8f2bc0105b973ee', {
couponName: coupon?.name,
})
)
}
description={
couponLoading ? (
ansmonjol marked this conversation as resolved.
Show resolved Hide resolved
<>
<Skeleton className="mb-4 w-full" variant="text" />
<Skeleton className="w-full" variant="text" />
</>
) : !!coupon?.appliedCouponsCount ? (
<Typography
html={translate(
'text_17364422965884zgujkr1l7j',
{ appliedCouponsCount: coupon.appliedCouponsCount },
coupon.appliedCouponsCount,
)}
/>
) : (
<Typography html={translate('text_628b432fd8f2bc0105b973f6')} />
)
}
disableOnContinue={couponLoading}
onContinue={async () =>
await deleteCoupon({
variables: { input: { id: coupon?.id || '' } },
Expand Down
12 changes: 11 additions & 1 deletion src/components/coupons/TerminateCouponDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { forwardRef, useImperativeHandle, useRef, useState } from 'react'
import { DialogRef, Typography } from '~/components/designSystem'
import { WarningDialog } from '~/components/WarningDialog'
import { addToast } from '~/core/apolloClient'
import { TerminateCouponFragment, useTerminateCouponMutation } from '~/generated/graphql'
import {
CouponDetailsFragmentDoc,
CouponItemFragmentDoc,
TerminateCouponFragment,
useTerminateCouponMutation,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'

gql`
Expand All @@ -16,8 +21,13 @@ gql`
mutation terminateCoupon($input: TerminateCouponInput!) {
terminateCoupon(input: $input) {
id
...CouponDetails
...CouponItem
}
}

${CouponDetailsFragmentDoc}
${CouponItemFragmentDoc}
`

export interface TerminateCouponDialogRef {
Expand Down
17 changes: 17 additions & 0 deletions src/core/constants/statusCouponMapping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { StatusProps, StatusType } from '~/components/designSystem'
import { CouponStatusEnum } from '~/generated/graphql'

export const couponStatusMapping = (type?: CouponStatusEnum | undefined): StatusProps => {
switch (type) {
case CouponStatusEnum.Active:
return {
type: StatusType.success,
label: 'active',
}
default:
return {
type: StatusType.danger,
label: 'terminated',
}
}
}
118 changes: 91 additions & 27 deletions src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6443,7 +6443,14 @@ export type CouponCaptionFragment = { __typename?: 'Coupon', id: string, amountC

export type AppliedCouponCaptionFragment = { __typename?: 'AppliedCoupon', id: string, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, amountCentsRemaining?: any | null, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null, frequencyDurationRemaining?: number | null };

export type DeleteCouponFragment = { __typename?: 'Coupon', id: string, name: string };
export type DeleteCouponFragment = { __typename?: 'Coupon', id: string, name: string, appliedCouponsCount: number };

export type GetCouponToDeleteQueryVariables = Exact<{
id: Scalars['ID']['input'];
}>;


export type GetCouponToDeleteQuery = { __typename?: 'Query', coupon?: { __typename?: 'Coupon', id: string, name: string, appliedCouponsCount: number } | null };

export type DeleteCouponMutationVariables = Exact<{
input: DestroyCouponInput;
Expand All @@ -6459,7 +6466,7 @@ export type TerminateCouponMutationVariables = Exact<{
}>;


export type TerminateCouponMutation = { __typename?: 'Mutation', terminateCoupon?: { __typename?: 'Coupon', id: string } | null };
export type TerminateCouponMutation = { __typename?: 'Mutation', terminateCoupon?: { __typename?: 'Coupon', id: string, amountCents?: any | null, amountCurrency?: CurrencyEnum | null, percentageRate?: number | null, code?: string | null, expirationAt?: any | null, name: string, frequency: CouponFrequency, reusable: boolean, couponType: CouponTypeEnum, status: CouponStatusEnum, customersCount: number, expiration: CouponExpiration, frequencyDuration?: number | null, billableMetrics?: Array<{ __typename?: 'BillableMetric', id: string, name: string }> | null, plans?: Array<{ __typename?: 'Plan', id: string, name: string }> | null } | null };

export type InvoiceForCreditNoteFormCalculationFragment = { __typename?: 'Invoice', id: string, couponsAmountCents: any, paymentStatus: InvoicePaymentStatusTypeEnum, creditableAmountCents: any, refundableAmountCents: any, feesAmountCents: any, currency?: CurrencyEnum | null, versionNumber: number, paymentDisputeLostAt?: any | null, fees?: Array<{ __typename?: 'Fee', id: string, appliedTaxes?: Array<{ __typename?: 'FeeAppliedTax', id: string, taxName: string, taxRate: number }> | null }> | null };

Expand Down Expand Up @@ -8170,7 +8177,7 @@ export type UpdateCouponMutationVariables = Exact<{
}>;


export type UpdateCouponMutation = { __typename?: 'Mutation', updateCoupon?: { __typename?: 'Coupon', id: string, name: string, customersCount: number, status: CouponStatusEnum, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, appliedCouponsCount: number, expiration: CouponExpiration, expirationAt?: any | null, couponType: CouponTypeEnum, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null } | null };
export type UpdateCouponMutation = { __typename?: 'Mutation', updateCoupon?: { __typename?: 'Coupon', id: string, name: string, customersCount: number, status: CouponStatusEnum, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, expiration: CouponExpiration, expirationAt?: any | null, couponType: CouponTypeEnum, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null } | null };

export type CustomerForExternalAppsAccordionFragment = { __typename?: 'Customer', id: string, customerType?: CustomerTypeEnum | null, currency?: CurrencyEnum | null, paymentProvider?: ProviderTypeEnum | null, paymentProviderCode?: string | null, netsuiteCustomer?: { __typename: 'NetsuiteCustomer', id: string, integrationId?: string | null, externalCustomerId?: string | null, integrationCode?: string | null, integrationType?: IntegrationTypeEnum | null, subsidiaryId?: string | null, syncWithProvider?: boolean | null } | null, anrokCustomer?: { __typename: 'AnrokCustomer', id: string, integrationId?: string | null, externalCustomerId?: string | null, integrationCode?: string | null, integrationType?: IntegrationTypeEnum | null, syncWithProvider?: boolean | null } | null, xeroCustomer?: { __typename: 'XeroCustomer', id: string, integrationId?: string | null, externalCustomerId?: string | null, integrationCode?: string | null, integrationType?: IntegrationTypeEnum | null, syncWithProvider?: boolean | null } | null, hubspotCustomer?: { __typename: 'HubspotCustomer', id: string, integrationId?: string | null, externalCustomerId?: string | null, integrationCode?: string | null, integrationType?: IntegrationTypeEnum | null, syncWithProvider?: boolean | null } | null, salesforceCustomer?: { __typename: 'SalesforceCustomer', id: string, integrationId?: string | null, externalCustomerId?: string | null, integrationCode?: string | null, integrationType?: IntegrationTypeEnum | null, syncWithProvider?: boolean | null } | null, providerCustomer?: { __typename?: 'ProviderCustomer', id: string, providerCustomerId?: string | null, syncWithProvider?: boolean | null, providerPaymentMethods?: Array<ProviderPaymentMethodsEnum> | null } | null };

Expand Down Expand Up @@ -8336,14 +8343,16 @@ export type BillableMetricsQueryVariables = Exact<{

export type BillableMetricsQuery = { __typename?: 'Query', billableMetrics: { __typename?: 'BillableMetricCollection', metadata: { __typename?: 'CollectionMetadata', currentPage: number, totalPages: number }, collection: Array<{ __typename?: 'BillableMetric', id: string, name: string, code: string, createdAt: any }> } };

export type CouponDetailsFragment = { __typename?: 'Coupon', amountCents?: any | null, amountCurrency?: CurrencyEnum | null, percentageRate?: number | null, code?: string | null, expirationAt?: any | null, name: string, frequency: CouponFrequency, reusable: boolean, couponType: CouponTypeEnum, status: CouponStatusEnum, billableMetrics?: Array<{ __typename?: 'BillableMetric', id: string, name: string }> | null, plans?: Array<{ __typename?: 'Plan', id: string, name: string }> | null };

export type GetCouponForDetailsQueryVariables = Exact<{
id: Scalars['ID']['input'];
}>;


export type GetCouponForDetailsQuery = { __typename?: 'Query', coupon?: { __typename?: 'Coupon', id: string, amountCents?: any | null, amountCurrency?: CurrencyEnum | null, percentageRate?: number | null, code?: string | null, expirationAt?: any | null, name: string, frequency: CouponFrequency, reusable: boolean, couponType: CouponTypeEnum, billableMetrics?: Array<{ __typename?: 'BillableMetric', id: string, name: string }> | null, plans?: Array<{ __typename?: 'Plan', id: string, name: string }> | null } | null };
export type GetCouponForDetailsQuery = { __typename?: 'Query', coupon?: { __typename?: 'Coupon', id: string, amountCents?: any | null, amountCurrency?: CurrencyEnum | null, percentageRate?: number | null, code?: string | null, expirationAt?: any | null, name: string, frequency: CouponFrequency, reusable: boolean, couponType: CouponTypeEnum, status: CouponStatusEnum, appliedCouponsCount: number, billableMetrics?: Array<{ __typename?: 'BillableMetric', id: string, name: string }> | null, plans?: Array<{ __typename?: 'Plan', id: string, name: string }> | null } | null };

export type CouponItemFragment = { __typename?: 'Coupon', id: string, name: string, customersCount: number, status: CouponStatusEnum, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, appliedCouponsCount: number, expiration: CouponExpiration, expirationAt?: any | null, couponType: CouponTypeEnum, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null };
export type CouponItemFragment = { __typename?: 'Coupon', id: string, name: string, customersCount: number, status: CouponStatusEnum, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, expiration: CouponExpiration, expirationAt?: any | null, couponType: CouponTypeEnum, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null };

export type CouponsQueryVariables = Exact<{
page?: InputMaybe<Scalars['Int']['input']>;
Expand All @@ -8352,7 +8361,7 @@ export type CouponsQueryVariables = Exact<{
}>;


export type CouponsQuery = { __typename?: 'Query', coupons: { __typename?: 'CouponCollection', metadata: { __typename?: 'CollectionMetadata', currentPage: number, totalPages: number }, collection: Array<{ __typename?: 'Coupon', id: string, name: string, customersCount: number, status: CouponStatusEnum, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, appliedCouponsCount: number, expiration: CouponExpiration, expirationAt?: any | null, couponType: CouponTypeEnum, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null }> } };
export type CouponsQuery = { __typename?: 'Query', coupons: { __typename?: 'CouponCollection', metadata: { __typename?: 'CollectionMetadata', currentPage: number, totalPages: number }, collection: Array<{ __typename?: 'Coupon', id: string, name: string, customersCount: number, status: CouponStatusEnum, amountCurrency?: CurrencyEnum | null, amountCents?: any | null, expiration: CouponExpiration, expirationAt?: any | null, couponType: CouponTypeEnum, percentageRate?: number | null, frequency: CouponFrequency, frequencyDuration?: number | null, appliedCouponsCount: number }> } };

export type GetTaxesForAddOnFormQueryVariables = Exact<{
limit?: InputMaybe<Scalars['Int']['input']>;
Expand Down Expand Up @@ -9207,6 +9216,7 @@ export const DeleteCouponFragmentDoc = gql`
fragment DeleteCoupon on Coupon {
id
name
appliedCouponsCount
}
`;
export const TerminateCouponFragmentDoc = gql`
Expand Down Expand Up @@ -10635,6 +10645,28 @@ export const BillableMetricItemFragmentDoc = gql`
createdAt
}
`;
export const CouponDetailsFragmentDoc = gql`
fragment CouponDetails on Coupon {
amountCents
amountCurrency
percentageRate
code
expirationAt
name
frequency
reusable
couponType
status
billableMetrics {
id
name
}
plans {
id
name
}
}
`;
export const CouponItemFragmentDoc = gql`
fragment CouponItem on Coupon {
id
Expand All @@ -10643,7 +10675,6 @@ export const CouponItemFragmentDoc = gql`
status
amountCurrency
amountCents
appliedCouponsCount
expiration
expirationAt
couponType
Expand Down Expand Up @@ -12511,6 +12542,46 @@ export type GetPlansForCouponsQueryHookResult = ReturnType<typeof useGetPlansFor
export type GetPlansForCouponsLazyQueryHookResult = ReturnType<typeof useGetPlansForCouponsLazyQuery>;
export type GetPlansForCouponsSuspenseQueryHookResult = ReturnType<typeof useGetPlansForCouponsSuspenseQuery>;
export type GetPlansForCouponsQueryResult = Apollo.QueryResult<GetPlansForCouponsQuery, GetPlansForCouponsQueryVariables>;
export const GetCouponToDeleteDocument = gql`
query getCouponToDelete($id: ID!) {
coupon(id: $id) {
...DeleteCoupon
}
}
${DeleteCouponFragmentDoc}`;

/**
* __useGetCouponToDeleteQuery__
*
* To run a query within a React component, call `useGetCouponToDeleteQuery` and pass it any options that fit your needs.
* When your component renders, `useGetCouponToDeleteQuery` 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 } = useGetCouponToDeleteQuery({
* variables: {
* id: // value for 'id'
* },
* });
*/
export function useGetCouponToDeleteQuery(baseOptions: Apollo.QueryHookOptions<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables> & ({ variables: GetCouponToDeleteQueryVariables; skip?: boolean; } | { skip: boolean; }) ) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables>(GetCouponToDeleteDocument, options);
}
export function useGetCouponToDeleteLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables>(GetCouponToDeleteDocument, options);
}
export function useGetCouponToDeleteSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables>) {
const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables>(GetCouponToDeleteDocument, options);
}
export type GetCouponToDeleteQueryHookResult = ReturnType<typeof useGetCouponToDeleteQuery>;
export type GetCouponToDeleteLazyQueryHookResult = ReturnType<typeof useGetCouponToDeleteLazyQuery>;
export type GetCouponToDeleteSuspenseQueryHookResult = ReturnType<typeof useGetCouponToDeleteSuspenseQuery>;
export type GetCouponToDeleteQueryResult = Apollo.QueryResult<GetCouponToDeleteQuery, GetCouponToDeleteQueryVariables>;
export const DeleteCouponDocument = gql`
mutation deleteCoupon($input: DestroyCouponInput!) {
destroyCoupon(input: $input) {
Expand Down Expand Up @@ -12548,9 +12619,12 @@ export const TerminateCouponDocument = gql`
mutation terminateCoupon($input: TerminateCouponInput!) {
terminateCoupon(input: $input) {
id
...CouponDetails
...CouponItem
}
}
`;
${CouponDetailsFragmentDoc}
${CouponItemFragmentDoc}`;
export type TerminateCouponMutationFn = Apollo.MutationFunction<TerminateCouponMutation, TerminateCouponMutationVariables>;

/**
Expand Down Expand Up @@ -21021,26 +21095,14 @@ export const GetCouponForDetailsDocument = gql`
query getCouponForDetails($id: ID!) {
coupon(id: $id) {
id
amountCents
amountCurrency
percentageRate
code
expirationAt
name
frequency
reusable
couponType
billableMetrics {
id
name
}
plans {
id
name
}
...CouponDetails
...DeleteCoupon
...TerminateCoupon
}
}
`;
${CouponDetailsFragmentDoc}
${DeleteCouponFragmentDoc}
${TerminateCouponFragmentDoc}`;

/**
* __useGetCouponForDetailsQuery__
Expand Down Expand Up @@ -21084,11 +21146,13 @@ export const CouponsDocument = gql`
collection {
...CouponItem
...CouponCaption
...DeleteCoupon
}
}
}
${CouponItemFragmentDoc}
${CouponCaptionFragmentDoc}`;
${CouponCaptionFragmentDoc}
${DeleteCouponFragmentDoc}`;

/**
* __useCouponsQuery__
Expand Down
Loading
Loading