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

feat: Cascade parent plan changes #1818

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
92 changes: 92 additions & 0 deletions src/components/plans/ImpactOverridenSubscriptionsDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useFormik } from 'formik'
import { forwardRef, useImperativeHandle, useRef, useState } from 'react'
import { boolean, object } from 'yup'

import { Button, Dialog, DialogRef } from '~/components/designSystem'
import { RadioGroupField } from '~/components/form'
import { useInternationalization } from '~/hooks/core/useInternationalization'

type ImpactOverridenSubscriptionsDialogProps = {
onSave: (value: boolean) => void
}

export type ImpactOverridenSubscriptionsDialogRef = {
openDialog: ({ onSave }: ImpactOverridenSubscriptionsDialogProps) => void
closeDialog: () => void
}

export const ImpactOverridenSubscriptionsDialog = forwardRef<ImpactOverridenSubscriptionsDialogRef>(
(_, ref) => {
const { translate } = useInternationalization()
const dialogRef = useRef<DialogRef>(null)
const [localData, setLocalData] = useState<ImpactOverridenSubscriptionsDialogProps>()

const formikProps = useFormik<{ cascadeUpdates: boolean }>({
initialValues: {
cascadeUpdates: false,
},
validateOnMount: true,
enableReinitialize: true,
validationSchema: object().shape({
cascadeUpdates: boolean().required(),
}),
onSubmit: async (values) => {
localData?.onSave?.(values.cascadeUpdates)

dialogRef?.current?.closeDialog()
},
})

useImperativeHandle(ref, () => ({
openDialog: (data) => {
formikProps.resetForm()
setLocalData(data)
dialogRef.current?.openDialog()
},
closeDialog: () => {
setLocalData(undefined)
dialogRef.current?.closeDialog()
},
}))

return (
<Dialog
ref={dialogRef}
title={translate('text_1729604107534r3hsj7i64gp')}
description={translate('text_17296041075348k56saczddu')}
actions={({ closeDialog }) => (
<div className="mt-8 flex gap-3">
<Button variant="quaternary" onClick={closeDialog}>
{translate('text_6271200984178801ba8bdf4a')}
</Button>

<Button variant="primary" onClick={formikProps.submitForm}>
{translate('text_1729604107534dfyz8j53ho5')}
</Button>
</div>
)}
>
<RadioGroupField
name="cascadeUpdates"
formikProps={formikProps}
optionsGapSpacing={4}
optionLabelVariant="body"
options={[
{
label: translate('text_17296041075346803c5xv8um'),
sublabel: translate('text_1729604107534v8b3vembdla'),
value: false,
},
{
label: translate('text_1729604107534vznb0h27kje'),
sublabel: translate('text_1729604107534rrec9gxuh54'),
value: true,
},
]}
/>
</Dialog>
)
},
)

ImpactOverridenSubscriptionsDialog.displayName = 'ImpactOverridenSubscriptionsDialog'
1 change: 1 addition & 0 deletions src/components/plans/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ export type PlanFormInput = Omit<
// NOTE: this is used for display purpose but will be replaced by usageThresholds[] on save
nonRecurringUsageThresholds?: LocalUsageThresholdInput[]
recurringUsageThreshold?: LocalUsageThresholdInput
cascadeUpdates?: boolean
}
2 changes: 2 additions & 0 deletions src/core/serializers/serializePlanInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export const serializePlanInput = (values: PlanFormInput) => {
minimumCommitment,
nonRecurringUsageThresholds,
recurringUsageThreshold,
cascadeUpdates,
...otherValues
} = values

Expand Down Expand Up @@ -191,6 +192,7 @@ export const serializePlanInput = (values: PlanFormInput) => {
}
},
),
...(typeof cascadeUpdates === 'undefined' ? {} : { cascadeUpdates }),
...otherValues,
}
}
11 changes: 7 additions & 4 deletions src/generated/graphql.tsx

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/hooks/customer/useAddSubscription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const cleanPlanValues = (planValues: PlanOverridesInput, formType: keyof typeof
taxes: undefined,
payInAdvance: undefined,
billChargesMonthly: undefined,
cascadeUpdates: undefined,
charges: planValues?.charges?.map((charge) => ({
...charge,
taxes: undefined,
Expand Down
4 changes: 3 additions & 1 deletion src/hooks/plans/usePlanForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { gql } from '@apollo/client'
import { FormikProps, useFormik } from 'formik'
import { useEffect, useMemo } from 'react'
import { generatePath, useNavigate, useParams, useSearchParams } from 'react-router-dom'
import { array, number, object, string } from 'yup'
import { array, boolean, number, object, string } from 'yup'

import { LocalChargeInput, PlanFormInput } from '~/components/plans/types'
import { transformFilterObjectToString } from '~/components/plans/utils'
Expand Down Expand Up @@ -230,6 +230,7 @@ export const usePlanForm: ({
}),
) as LocalChargeInput[])
: ([] as LocalChargeInput[]),
cascadeUpdates: undefined,
},
validationSchema: object().shape({
name: string().required(''),
Expand Down Expand Up @@ -311,6 +312,7 @@ export const usePlanForm: ({
})
.nullable()
.default(undefined),
cascadeUpdates: boolean(),
}),
enableReinitialize: true,
validateOnMount: true,
Expand Down
22 changes: 21 additions & 1 deletion src/pages/CreatePlan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
import { ChargesSection } from '~/components/plans/ChargesSection'
import { CommitmentsSection } from '~/components/plans/CommitmentsSection'
import { FixedFeeSection } from '~/components/plans/FixedFeeSection'
import {
ImpactOverridenSubscriptionsDialog,
ImpactOverridenSubscriptionsDialogRef,
} from '~/components/plans/ImpactOverridenSubscriptionsDialog'
import { PlanCodeSnippet } from '~/components/plans/PlanCodeSnippet'
import { PlanSettingsSection } from '~/components/plans/PlanSettingsSection'
import { ProgressiveBillingSection } from '~/components/plans/ProgressiveBillingSection'
Expand Down Expand Up @@ -75,6 +79,7 @@ gql`
trialPeriod
subscriptionsCount
billChargesMonthly
hasOverriddenPlans
minimumCommitment {
amountCents
commitmentType
Expand Down Expand Up @@ -128,6 +133,7 @@ const CreatePlan = () => {
const premiumWarningDialogRef = useRef<PremiumWarningDialogRef>(null)
const { errorCode, formikProps, isEdition, loading, plan, type } = usePlanForm({})
const warningDialogRef = useRef<WarningDialogRef>(null)
const impactOverridenSubscriptionsDialogRef = useRef<ImpactOverridenSubscriptionsDialogRef>(null)
const editInvoiceDisplayNameRef = useRef<EditInvoiceDisplayNameRef>(null)

const canBeEdited = !plan?.subscriptionsCount
Expand Down Expand Up @@ -299,7 +305,19 @@ const CreatePlan = () => {
<Button
disabled={!formikProps.isValid || (isEdition && !formikProps.dirty)}
size="large"
onClick={formikProps.submitForm}
onClick={() => {
if (plan?.hasOverriddenPlans) {
return impactOverridenSubscriptionsDialogRef.current?.openDialog({
onSave: async (cascadeUpdates) => {
await formikProps.setFieldValue('cascadeUpdates', cascadeUpdates)

return formikProps.submitForm()
},
})
}

return formikProps.submitForm()
}}
data-test="submit"
>
{translate(
Expand All @@ -325,6 +343,8 @@ const CreatePlan = () => {
onContinue={() => planCloseRedirection()}
/>

<ImpactOverridenSubscriptionsDialog ref={impactOverridenSubscriptionsDialogRef} />

<EditInvoiceDisplayName ref={editInvoiceDisplayNameRef} />
<PremiumWarningDialog ref={premiumWarningDialogRef} />
</div>
Expand Down
9 changes: 8 additions & 1 deletion translations/base.json
Original file line number Diff line number Diff line change
Expand Up @@ -2572,5 +2572,12 @@
"text_1729262241097k3cnpci6p5j": "Prepaid credits",
"text_1729262339446mk289ygp31g": "Refund customer",
"text_17295725378539prq3x0wpry": "{{invoiceNumber}} for a remaining subtotal of {{subtotal}}",
"text_1730132579304cmiwba11ha6": "Received at"
"text_1730132579304cmiwba11ha6": "Received at",
"text_1729604107534r3hsj7i64gp": "Impact overridden subscriptions",
"text_17296041075348k56saczddu": "This plan is linked to overridden subscriptions. Any changes to a charge or filter will only apply to subscriptions that share the same price for that charge. Would you like to apply these changes to the relevant subscriptions?",
"text_17296041075346803c5xv8um": "Do not impact overridden subscriptions",
"text_1729604107534v8b3vembdla": "These changes will impact only non-overridden subscriptions.",
"text_1729604107534vznb0h27kje": "Impact overridden subscriptions",
"text_1729604107534rrec9gxuh54": "These changes will impact both overridden subscriptions and those not overridden.",
"text_1729604107534dfyz8j53ho5": "Save editions"
}
Loading