From c09e29c0406823481ff5ea13b90e2222b7b14f1e Mon Sep 17 00:00:00 2001 From: ilkin-overleaf <100852799+ilkin-overleaf@users.noreply.github.com> Date: Tue, 14 Feb 2023 10:17:02 +0200 Subject: [PATCH] Merge pull request #11751 from overleaf/ii-payment-page-stories [web] Payment page stories GitOrigin-RevId: 9f8aff0cf839bc811d8612e97bd627b577860cc8 --- .../components/new/checkout/submit-button.tsx | 4 +- .../subscription/context/payment-context.tsx | 4 +- .../js/shared/utils/external-script-loader.ts | 31 +++++++ .../checkout/address-first-line.stories.tsx | 64 +++++++++++++ .../checkout/address-second-line.stories.tsx | 64 +++++++++++++ .../new/checkout/card-element.stories.tsx | 40 ++++++++ .../new/checkout/company-details.stories.tsx | 65 +++++++++++++ .../new/checkout/country-select.stories.tsx | 74 +++++++++++++++ .../new/checkout/coupon-code.stories.tsx | 47 ++++++++++ .../new/checkout/first-name.stories.tsx | 61 ++++++++++++ .../new/checkout/last-name.stories.tsx | 61 ++++++++++++ .../payment-method-toggle.stories.tsx | 28 ++++++ .../new/checkout/postal-code.stories.tsx | 64 +++++++++++++ .../checkout/price-switch-header.stories.tsx | 43 +++++++++ .../new/checkout/submit-button.stories.tsx | 47 ++++++++++ .../checkout/tos-agreement-notice.stories.tsx | 17 ++++ .../new/helpers/context-provider.tsx | 13 +++ .../payment-preview/collaborators.stories.tsx | 40 ++++++++ .../payment-preview/features-list.stories.tsx | 33 +++++++ .../no-discount-price.stories.tsx | 93 +++++++++++++++++++ .../price-for-first-x-period.stories.tsx | 75 +++++++++++++++ .../payment-preview/price-summary.stories.tsx | 51 ++++++++++ .../payment-preview/trial-price.stories.tsx | 33 +++++++ 23 files changed, 1049 insertions(+), 3 deletions(-) create mode 100644 services/web/frontend/js/shared/utils/external-script-loader.ts create mode 100644 services/web/frontend/stories/subscription/new/checkout/address-first-line.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/address-second-line.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/card-element.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/company-details.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/country-select.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/coupon-code.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/first-name.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/last-name.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/payment-method-toggle.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/postal-code.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/price-switch-header.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/submit-button.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/checkout/tos-agreement-notice.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/helpers/context-provider.tsx create mode 100644 services/web/frontend/stories/subscription/new/payment-preview/collaborators.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/payment-preview/features-list.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/payment-preview/no-discount-price.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/payment-preview/price-for-first-x-period.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/payment-preview/price-summary.stories.tsx create mode 100644 services/web/frontend/stories/subscription/new/payment-preview/trial-price.stories.tsx diff --git a/services/web/frontend/js/features/subscription/components/new/checkout/submit-button.tsx b/services/web/frontend/js/features/subscription/components/new/checkout/submit-button.tsx index 9bc2afc669..e2e28bf685 100644 --- a/services/web/frontend/js/features/subscription/components/new/checkout/submit-button.tsx +++ b/services/web/frontend/js/features/subscription/components/new/checkout/submit-button.tsx @@ -2,13 +2,13 @@ import { useTranslation } from 'react-i18next' import { Button } from 'react-bootstrap' import Icon from '../../../../../shared/components/icon' -type CardSubmitButtonProps = { +type SubmitButtonProps = { isProcessing: boolean isFormValid: boolean children: React.ReactNode } -function SubmitButton(props: CardSubmitButtonProps) { +function SubmitButton(props: SubmitButtonProps) { const { t } = useTranslation() return ( diff --git a/services/web/frontend/js/features/subscription/context/payment-context.tsx b/services/web/frontend/js/features/subscription/context/payment-context.tsx index 65059dfbe1..906ab16954 100644 --- a/services/web/frontend/js/features/subscription/context/payment-context.tsx +++ b/services/web/frontend/js/features/subscription/context/payment-context.tsx @@ -333,7 +333,9 @@ function usePayment({ publicKey }: RecurlyOptions) { return { value } } -const PaymentContext = createContext(undefined) +export const PaymentContext = createContext( + undefined +) type PaymentProviderProps = { publicKey: string diff --git a/services/web/frontend/js/shared/utils/external-script-loader.ts b/services/web/frontend/js/shared/utils/external-script-loader.ts new file mode 100644 index 0000000000..fda17e5e32 --- /dev/null +++ b/services/web/frontend/js/shared/utils/external-script-loader.ts @@ -0,0 +1,31 @@ +import { useState, useEffect } from 'react' + +type ExternalScriptLoaderProps = { + children: JSX.Element + src: string +} + +function ExternalScriptLoader({ children, src }: ExternalScriptLoaderProps) { + const [loaded, setLoaded] = useState(false) + + useEffect(() => { + const body = document.querySelector('body') + const script = document.createElement('script') + + script.async = true + script.src = src + script.onload = () => { + setLoaded(true) + } + + body?.appendChild(script) + + return () => { + body?.removeChild(script) + } + }, [src]) + + return loaded ? children : null +} + +export default ExternalScriptLoader diff --git a/services/web/frontend/stories/subscription/new/checkout/address-first-line.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/address-first-line.stories.tsx new file mode 100644 index 0000000000..86907d72e7 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/address-first-line.stories.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react' +import AddressFirstLineComponent from '../../../../js/features/subscription/components/new/checkout/address-first-line' + +type Args = Pick< + React.ComponentProps, + 'errorFields' +> + +const Template = ({ errorFields }: Args) => { + const [value, setValue] = useState('') + + return ( + setValue(e.target.value)} + /> + ) +} + +export const AddressFirstLineDefault = Template.bind({}) as typeof Template & { + args: Args +} +AddressFirstLineDefault.args = { + errorFields: { + address1: false, + }, +} + +export const AddressFirstLineError = Template.bind({}) as typeof Template & { + args: Args +} +AddressFirstLineError.args = { + errorFields: { + address1: true, + }, +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: AddressFirstLineComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/address-second-line.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/address-second-line.stories.tsx new file mode 100644 index 0000000000..6c281d0fe0 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/address-second-line.stories.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react' +import AddressSecondLineComponent from '../../../../js/features/subscription/components/new/checkout/address-second-line' + +type Args = Pick< + React.ComponentProps, + 'errorFields' +> + +const Template = ({ errorFields }: Args) => { + const [value, setValue] = useState('') + + return ( + setValue(e.target.value)} + /> + ) +} + +export const AddressSecondLineDefault = Template.bind({}) as typeof Template & { + args: Args +} +AddressSecondLineDefault.args = { + errorFields: { + address2: false, + }, +} + +export const AddressSecondLineError = Template.bind({}) as typeof Template & { + args: Args +} +AddressSecondLineError.args = { + errorFields: { + address2: true, + }, +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: AddressSecondLineComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/card-element.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/card-element.stories.tsx new file mode 100644 index 0000000000..2d4be68294 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/card-element.stories.tsx @@ -0,0 +1,40 @@ +import { useRef } from 'react' +import CardElementComponent from '../../../../js/features/subscription/components/new/checkout/card-element' +import ExternalScriptLoader from '../../../../js/shared/utils/external-script-loader' + +export const CardElement = () => { + const elements = useRef(recurly.Elements()) + + return ( + {}} /> + ) +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: CardElementComponent, + argTypes: { + elements: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ + + +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/company-details.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/company-details.stories.tsx new file mode 100644 index 0000000000..731fc49449 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/company-details.stories.tsx @@ -0,0 +1,65 @@ +import { useState } from 'react' +import CompanyDetailsComponent from '../../../../js/features/subscription/components/new/checkout/company-details' +import { PaymentProvider } from '../helpers/context-provider' +import { + PaymentContextValue, + PricingFormState, +} from '../../../../js/features/subscription/context/types/payment-context-value' + +type Args = Pick< + React.ComponentProps, + 'taxesCount' +> + +export const CompanyDetails = (args: Args) => { + const [pricingFormState, setPricingFormState] = useState({ + first_name: '', + last_name: '', + postal_code: '', + address1: '', + address2: '', + state: '', + city: '', + company: '', + vat_number: '', + country: 'GB', + coupon: '', + }) + + const providerValue = { + applyVatNumber: () => {}, + pricingFormState, + setPricingFormState, + } as unknown as PaymentContextValue + + return ( + + + + ) +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: CompanyDetailsComponent, + argTypes: { + taxesCount: { + control: { + type: 'number', + }, + }, + }, + args: { + taxesCount: 1, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/country-select.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/country-select.stories.tsx new file mode 100644 index 0000000000..ad54c290e3 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/country-select.stories.tsx @@ -0,0 +1,74 @@ +import { useState } from 'react' +import countries from '../../../../js/features/subscription/data/countries' +import CountrySelectComponent from '../../../../js/features/subscription/components/new/checkout/country-select' +import { PaymentProvider } from '../helpers/context-provider' +import { PaymentContextValue } from '../../../../js/features/subscription/context/types/payment-context-value' + +type Args = Pick< + React.ComponentProps, + 'errorFields' +> + +const Template = ({ errorFields }: Args) => { + const [value, setValue] = useState('GB') + const providerValue = { + updateCountry: () => {}, + } as unknown as PaymentContextValue + + return ( + + + setValue(e.target.value as typeof countries[number]['code']) + } + /> + + ) +} + +export const CountrySelectDefault = Template.bind({}) as typeof Template & { + args: Args +} +CountrySelectDefault.args = { + errorFields: { + country: false, + }, +} + +export const CountrySelectError = Template.bind({}) as typeof Template & { + args: Args +} +CountrySelectError.args = { + errorFields: { + country: true, + }, +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: CountrySelectComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/coupon-code.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/coupon-code.stories.tsx new file mode 100644 index 0000000000..f424d4c543 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/coupon-code.stories.tsx @@ -0,0 +1,47 @@ +import { useState } from 'react' +import CouponCodeComponent from '../../../../js/features/subscription/components/new/checkout/coupon-code' +import { PaymentProvider } from '../helpers/context-provider' +import { PaymentContextValue } from '../../../../js/features/subscription/context/types/payment-context-value' + +export const CouponCode = () => { + const [value, setValue] = useState('') + const providerValue = { + addCoupon: () => {}, + } as unknown as PaymentContextValue + + return ( + + setValue(e.target.value)} + /> + + ) +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: CouponCodeComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/first-name.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/first-name.stories.tsx new file mode 100644 index 0000000000..717713b66e --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/first-name.stories.tsx @@ -0,0 +1,61 @@ +import { useState } from 'react' +import FirstNameComponent from '../../../../js/features/subscription/components/new/checkout/first-name' + +type Args = Pick, 'errorFields'> + +const Template = ({ errorFields }: Args) => { + const [value, setValue] = useState('') + + return ( + setValue(e.target.value)} + /> + ) +} + +export const FirstNameDefault = Template.bind({}) as typeof Template & { + args: Args +} +FirstNameDefault.args = { + errorFields: { + first_name: false, + }, +} + +export const FirstNameError = Template.bind({}) as typeof Template & { + args: Args +} +FirstNameError.args = { + errorFields: { + first_name: true, + }, +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: FirstNameComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/last-name.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/last-name.stories.tsx new file mode 100644 index 0000000000..c33fc97ff6 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/last-name.stories.tsx @@ -0,0 +1,61 @@ +import { useState } from 'react' +import LastNameComponent from '../../../../js/features/subscription/components/new/checkout/last-name' + +type Args = Pick, 'errorFields'> + +const Template = ({ errorFields }: Args) => { + const [value, setValue] = useState('') + + return ( + setValue(e.target.value)} + /> + ) +} + +export const LastNameDefault = Template.bind({}) as typeof Template & { + args: Args +} +LastNameDefault.args = { + errorFields: { + last_name: false, + }, +} + +export const LastNameError = Template.bind({}) as typeof Template & { + args: Args +} +LastNameError.args = { + errorFields: { + last_name: true, + }, +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: LastNameComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/payment-method-toggle.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/payment-method-toggle.stories.tsx new file mode 100644 index 0000000000..498ba513d0 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/payment-method-toggle.stories.tsx @@ -0,0 +1,28 @@ +import { useState } from 'react' +import PaymentMethodToggleComponent from '../../../../js/features/subscription/components/new/checkout/payment-method-toggle' + +export const PaymentMethodToggle = () => { + const [paymentMethod, setPaymentMethod] = useState('credit_card') + + return ( + setPaymentMethod(e.target.value)} + /> + ) +} + +export default { + title: 'Subscription / New / Checkout', + component: PaymentMethodToggleComponent, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/postal-code.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/postal-code.stories.tsx new file mode 100644 index 0000000000..e7b483b24f --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/postal-code.stories.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react' +import PostalCodeComponent from '../../../../js/features/subscription/components/new/checkout/postal-code' + +type Args = Pick< + React.ComponentProps, + 'errorFields' +> + +const Template = ({ errorFields }: Args) => { + const [value, setValue] = useState('') + + return ( + setValue(e.target.value)} + /> + ) +} + +export const PostalCodeDefault = Template.bind({}) as typeof Template & { + args: Args +} +PostalCodeDefault.args = { + errorFields: { + postal_code: false, + }, +} + +export const PostalCodeError = Template.bind({}) as typeof Template & { + args: Args +} +PostalCodeError.args = { + errorFields: { + postal_code: true, + }, +} + +export default { + title: 'Subscription / New / Checkout / Form Fields', + component: PostalCodeComponent, + argTypes: { + value: { + table: { + disable: true, + }, + }, + onChange: { + table: { + disable: true, + }, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/price-switch-header.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/price-switch-header.stories.tsx new file mode 100644 index 0000000000..2e560b862c --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/price-switch-header.stories.tsx @@ -0,0 +1,43 @@ +import PriceSwitchHeaderComponent from '../../../../js/features/subscription/components/new/checkout/price-switch-header' + +type Args = React.ComponentProps + +export const PriceSwitchHeader = (args: Args) => ( + +) + +const options = { + current: 'fake_plan', + other: 'fake_plan_new', +} + +export default { + title: 'Subscription / New / Checkout', + component: PriceSwitchHeaderComponent, + argTypes: { + planCode: { + options: Object.values(options), + control: { + type: 'select', + labels: Object.entries(options).reduce( + (prev, [key, value]) => ({ ...prev, [String(value)]: key }), + {} + ), + }, + }, + }, + args: { + planCode: 'fake_plan', + planCodes: ['fake_plan'], + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/submit-button.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/submit-button.stories.tsx new file mode 100644 index 0000000000..91c9867a68 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/submit-button.stories.tsx @@ -0,0 +1,47 @@ +import SubmitButtonComponent from '../../../../js/features/subscription/components/new/checkout/submit-button' + +type Args = React.ComponentProps + +const Template = (args: Args) => + +export const SubmitButton = Template.bind({}) as typeof Template & { + args: Args +} +SubmitButton.args = { + isProcessing: false, + isFormValid: true, + children: 'Submit', +} + +export const SubmitButtonDisabled = Template.bind({}) as typeof Template & { + args: Args +} +SubmitButtonDisabled.args = { + isProcessing: false, + isFormValid: false, + children: 'Submit', +} + +export const SubmitButtonProcessing = Template.bind({}) as typeof Template & { + args: Args +} +SubmitButtonProcessing.args = { + isProcessing: true, + isFormValid: true, + children: 'Submit', +} + +export default { + title: 'Subscription / New / Checkout / Submit Button', + component: SubmitButtonComponent, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/checkout/tos-agreement-notice.stories.tsx b/services/web/frontend/stories/subscription/new/checkout/tos-agreement-notice.stories.tsx new file mode 100644 index 0000000000..8c90c8b67a --- /dev/null +++ b/services/web/frontend/stories/subscription/new/checkout/tos-agreement-notice.stories.tsx @@ -0,0 +1,17 @@ +import TosAgreementNoticeComponent from '../../../../js/features/subscription/components/new/checkout/tos-agreement-notice' + +export const TosAgreementNotice = () => + +export default { + title: 'Subscription / New / Checkout', + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/helpers/context-provider.tsx b/services/web/frontend/stories/subscription/new/helpers/context-provider.tsx new file mode 100644 index 0000000000..59fbff8c96 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/helpers/context-provider.tsx @@ -0,0 +1,13 @@ +import { PaymentContext } from '../../../../js/features/subscription/context/payment-context' +import { PaymentContextValue } from '../../../../js/features/subscription/context/types/payment-context-value' + +type PaymentProviderProps = { + children: React.ReactNode + value: PaymentContextValue +} + +export function PaymentProvider({ value, children }: PaymentProviderProps) { + return ( + {children} + ) +} diff --git a/services/web/frontend/stories/subscription/new/payment-preview/collaborators.stories.tsx b/services/web/frontend/stories/subscription/new/payment-preview/collaborators.stories.tsx new file mode 100644 index 0000000000..aace78dd5c --- /dev/null +++ b/services/web/frontend/stories/subscription/new/payment-preview/collaborators.stories.tsx @@ -0,0 +1,40 @@ +import CollaboratorsComponent from '../../../../js/features/subscription/components/new/payment-preview/collaborators' + +type Args = React.ComponentProps + +export const Collaborators = (args: Args) => ( + +) + +const options = { + unlimited: -1, + single: 1, + multiple: 2, +} + +export default { + title: 'Subscription / New / Payment Preview', + component: CollaboratorsComponent, + argTypes: { + count: { + options: Object.values(options), + control: { + type: 'select', + labels: Object.entries(options).reduce( + (prev, [key, value]) => ({ ...prev, [String(value)]: key }), + {} + ), + }, + }, + }, + args: { + count: options.single, // default + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/payment-preview/features-list.stories.tsx b/services/web/frontend/stories/subscription/new/payment-preview/features-list.stories.tsx new file mode 100644 index 0000000000..0380a1f3f3 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/payment-preview/features-list.stories.tsx @@ -0,0 +1,33 @@ +import FeaturesListComponent from '../../../../js/features/subscription/components/new/payment-preview/features-list' +import { Plan } from '../../../../../types/subscription/plan' + +type Args = React.ComponentProps + +export const FeaturesList = (args: Args) => + +const features = { + compileTimeout: 2, + dropbox: true, + github: true, + versioning: true, + trackChanges: true, + references: true, + mendeley: true, + zotero: true, + symbolPalette: true, +} as unknown as Plan['features'] + +export default { + title: 'Subscription / New / Payment Preview', + component: FeaturesListComponent, + args: { + features, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/payment-preview/no-discount-price.stories.tsx b/services/web/frontend/stories/subscription/new/payment-preview/no-discount-price.stories.tsx new file mode 100644 index 0000000000..8bd10ccb9e --- /dev/null +++ b/services/web/frontend/stories/subscription/new/payment-preview/no-discount-price.stories.tsx @@ -0,0 +1,93 @@ +import NoDiscountPriceComponent from '../../../../js/features/subscription/components/new/payment-preview/no-discount-price' +import { PaymentProvider } from '../helpers/context-provider' +import { PaymentContextValue } from '../../../../js/features/subscription/context/types/payment-context-value' + +type Args = Pick, 'value'> + +const Template = (args: Args) => { + return ( + + + + ) +} + +const commonValues = { + currencySymbol: '$', + coupon: { + normalPrice: 2, + }, +} + +export const ThenXPricePerMonth = Template.bind({}) as typeof Template & { + args: Args +} +const thenXPricePerMonthValue = { + ...commonValues, + monthlyBilling: true, + coupon: { + ...commonValues.coupon, + discountMonths: 2, + singleUse: false, + }, +} as PaymentContextValue +ThenXPricePerMonth.args = { + value: thenXPricePerMonthValue, +} + +export const ThenXPricePerYear = Template.bind({}) as typeof Template & { + args: Args +} +const thenXPricePerYearValue = { + ...commonValues, + monthlyBilling: false, + coupon: { + ...commonValues.coupon, + singleUse: true, + }, +} as PaymentContextValue +ThenXPricePerYear.args = { + value: thenXPricePerYearValue, +} + +export const NormallyXPricePerMonth = Template.bind({}) as typeof Template & { + args: Args +} +const normallyXPricePerMonthValue = { + ...commonValues, + monthlyBilling: true, + coupon: { + ...commonValues.coupon, + singleUse: false, + }, +} as PaymentContextValue +NormallyXPricePerMonth.args = { + value: normallyXPricePerMonthValue, +} + +export const NormallyXPricePerYear = Template.bind({}) as typeof Template & { + args: Args +} +const normallyXPricePerYearValue = { + ...commonValues, + monthlyBilling: false, + coupon: { + ...commonValues.coupon, + singleUse: false, + }, +} as PaymentContextValue +NormallyXPricePerYear.args = { + value: normallyXPricePerYearValue, +} + +export default { + title: 'Subscription / New / Payment Preview / No Discount Price', + component: NoDiscountPriceComponent, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/payment-preview/price-for-first-x-period.stories.tsx b/services/web/frontend/stories/subscription/new/payment-preview/price-for-first-x-period.stories.tsx new file mode 100644 index 0000000000..d94350d073 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/payment-preview/price-for-first-x-period.stories.tsx @@ -0,0 +1,75 @@ +import PriceForFirstXPeriod from '../../../../js/features/subscription/components/new/payment-preview/price-for-first-x-period' +import { PaymentProvider } from '../helpers/context-provider' +import { PaymentContextValue } from '../../../../js/features/subscription/context/types/payment-context-value' + +type Args = Pick, 'value'> + +const Template = (args: Args) => { + return ( + + + + ) +} + +const commonValues = { + currencySymbol: '$', + recurlyPrice: { + total: '10.00', + }, +} + +export const XPriceForYMonths = Template.bind({}) as typeof Template & { + args: Args +} +const xPriceForYMonthsValue = { + ...commonValues, + monthlyBilling: true, + coupon: { + discountMonths: 2, + singleUse: false, + }, +} as PaymentContextValue +XPriceForYMonths.args = { + value: xPriceForYMonthsValue, +} + +export const XPriceForFirstMonth = Template.bind({}) as typeof Template & { + args: Args +} +const xPriceForFirstMonthValue = { + ...commonValues, + monthlyBilling: true, + coupon: { + singleUse: true, + }, +} as PaymentContextValue +XPriceForFirstMonth.args = { + value: xPriceForFirstMonthValue, +} + +export const XPriceForFirstYear = Template.bind({}) as typeof Template & { + args: Args +} +const xPriceForFirstYearValue = { + ...commonValues, + monthlyBilling: false, + coupon: { + singleUse: true, + }, +} as PaymentContextValue +XPriceForFirstYear.args = { + value: xPriceForFirstYearValue, +} + +export default { + title: 'Subscription / New / Payment Preview / Price For First X Period', + component: PriceForFirstXPeriod, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/payment-preview/price-summary.stories.tsx b/services/web/frontend/stories/subscription/new/payment-preview/price-summary.stories.tsx new file mode 100644 index 0000000000..bc06733f87 --- /dev/null +++ b/services/web/frontend/stories/subscription/new/payment-preview/price-summary.stories.tsx @@ -0,0 +1,51 @@ +import PriceSummaryComponent from '../../../../js/features/subscription/components/new/payment-preview/price-summary' +import { PaymentProvider } from '../helpers/context-provider' + +type Args = Pick, 'value'> + +export const PriceSummary = (args: Args) => { + return ( + + + + ) +} + +export default { + title: 'Subscription / New / Payment Preview', + component: PriceSummaryComponent, + args: { + value: { + currencyCode: 'USD', + currencySymbol: '$', + coupon: { + name: 'react', + normalPriceWithoutTax: 15, + }, + changeCurrency: (_eventKey: string) => {}, + limitedCurrencies: { + USD: '$', + EUR: '€', + }, + monthlyBilling: true, + planName: 'Test plan', + recurlyPrice: { + discount: '3', + tax: '5.00', + total: '10.00', + }, + taxes: [ + { + rate: '1', + }, + ], + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +} diff --git a/services/web/frontend/stories/subscription/new/payment-preview/trial-price.stories.tsx b/services/web/frontend/stories/subscription/new/payment-preview/trial-price.stories.tsx new file mode 100644 index 0000000000..65edf0aa1b --- /dev/null +++ b/services/web/frontend/stories/subscription/new/payment-preview/trial-price.stories.tsx @@ -0,0 +1,33 @@ +import TrialPriceComponent from '../../../../js/features/subscription/components/new/payment-preview/trial-price' +import { PaymentProvider } from '../helpers/context-provider' + +type Args = Pick, 'value'> + +export const TrialPrice = (args: Args) => { + return ( + + + + ) +} + +export default { + title: 'Subscription / New / Payment Preview', + component: TrialPriceComponent, + args: { + value: { + currencySymbol: '$', + recurlyPrice: { + total: '10.00', + }, + trialLength: 7, + }, + }, + decorators: [ + (Story: React.ComponentType) => ( +
+ +
+ ), + ], +}