mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #11751 from overleaf/ii-payment-page-stories
[web] Payment page stories GitOrigin-RevId: 9f8aff0cf839bc811d8612e97bd627b577860cc8
This commit is contained in:
parent
9eff0140a9
commit
c09e29c040
23 changed files with 1049 additions and 3 deletions
|
@ -2,13 +2,13 @@ import { useTranslation } from 'react-i18next'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import Icon from '../../../../../shared/components/icon'
|
import Icon from '../../../../../shared/components/icon'
|
||||||
|
|
||||||
type CardSubmitButtonProps = {
|
type SubmitButtonProps = {
|
||||||
isProcessing: boolean
|
isProcessing: boolean
|
||||||
isFormValid: boolean
|
isFormValid: boolean
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
function SubmitButton(props: CardSubmitButtonProps) {
|
function SubmitButton(props: SubmitButtonProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -333,7 +333,9 @@ function usePayment({ publicKey }: RecurlyOptions) {
|
||||||
return { value }
|
return { value }
|
||||||
}
|
}
|
||||||
|
|
||||||
const PaymentContext = createContext<PaymentContextValue | undefined>(undefined)
|
export const PaymentContext = createContext<PaymentContextValue | undefined>(
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
|
||||||
type PaymentProviderProps = {
|
type PaymentProviderProps = {
|
||||||
publicKey: string
|
publicKey: string
|
||||||
|
|
|
@ -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
|
|
@ -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<typeof AddressFirstLineComponent>,
|
||||||
|
'errorFields'
|
||||||
|
>
|
||||||
|
|
||||||
|
const Template = ({ errorFields }: Args) => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AddressFirstLineComponent
|
||||||
|
errorFields={errorFields}
|
||||||
|
value={value}
|
||||||
|
onChange={e => 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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<typeof AddressSecondLineComponent>,
|
||||||
|
'errorFields'
|
||||||
|
>
|
||||||
|
|
||||||
|
const Template = ({ errorFields }: Args) => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AddressSecondLineComponent
|
||||||
|
errorFields={errorFields}
|
||||||
|
value={value}
|
||||||
|
onChange={e => 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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<CardElementComponent elements={elements.current} onChange={() => {}} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Subscription / New / Checkout / Form Fields',
|
||||||
|
component: CardElementComponent,
|
||||||
|
argTypes: {
|
||||||
|
elements: {
|
||||||
|
table: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onChange: {
|
||||||
|
table: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story: React.ComponentType) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<ExternalScriptLoader src="https://js.recurly.com/v4/recurly.js">
|
||||||
|
<Story />
|
||||||
|
</ExternalScriptLoader>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<typeof CompanyDetailsComponent>,
|
||||||
|
'taxesCount'
|
||||||
|
>
|
||||||
|
|
||||||
|
export const CompanyDetails = (args: Args) => {
|
||||||
|
const [pricingFormState, setPricingFormState] = useState<PricingFormState>({
|
||||||
|
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 (
|
||||||
|
<PaymentProvider value={providerValue}>
|
||||||
|
<CompanyDetailsComponent {...args} />
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Subscription / New / Checkout / Form Fields',
|
||||||
|
component: CompanyDetailsComponent,
|
||||||
|
argTypes: {
|
||||||
|
taxesCount: {
|
||||||
|
control: {
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
taxesCount: 1,
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story: React.ComponentType) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<typeof CountrySelectComponent>,
|
||||||
|
'errorFields'
|
||||||
|
>
|
||||||
|
|
||||||
|
const Template = ({ errorFields }: Args) => {
|
||||||
|
const [value, setValue] = useState<typeof countries[number]['code']>('GB')
|
||||||
|
const providerValue = {
|
||||||
|
updateCountry: () => {},
|
||||||
|
} as unknown as PaymentContextValue
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PaymentProvider value={providerValue}>
|
||||||
|
<CountrySelectComponent
|
||||||
|
errorFields={errorFields}
|
||||||
|
value={value}
|
||||||
|
onChange={e =>
|
||||||
|
setValue(e.target.value as typeof countries[number]['code'])
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<PaymentProvider value={providerValue}>
|
||||||
|
<CouponCodeComponent
|
||||||
|
value={value}
|
||||||
|
onChange={e => setValue(e.target.value)}
|
||||||
|
/>
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Subscription / New / Checkout / Form Fields',
|
||||||
|
component: CouponCodeComponent,
|
||||||
|
argTypes: {
|
||||||
|
value: {
|
||||||
|
table: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onChange: {
|
||||||
|
table: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story: React.ComponentType) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
import FirstNameComponent from '../../../../js/features/subscription/components/new/checkout/first-name'
|
||||||
|
|
||||||
|
type Args = Pick<React.ComponentProps<typeof FirstNameComponent>, 'errorFields'>
|
||||||
|
|
||||||
|
const Template = ({ errorFields }: Args) => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FirstNameComponent
|
||||||
|
errorFields={errorFields}
|
||||||
|
value={value}
|
||||||
|
onChange={e => 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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
import LastNameComponent from '../../../../js/features/subscription/components/new/checkout/last-name'
|
||||||
|
|
||||||
|
type Args = Pick<React.ComponentProps<typeof LastNameComponent>, 'errorFields'>
|
||||||
|
|
||||||
|
const Template = ({ errorFields }: Args) => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LastNameComponent
|
||||||
|
errorFields={errorFields}
|
||||||
|
value={value}
|
||||||
|
onChange={e => 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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<PaymentMethodToggleComponent
|
||||||
|
paymentMethod={paymentMethod}
|
||||||
|
onChange={e => setPaymentMethod(e.target.value)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Subscription / New / Checkout',
|
||||||
|
component: PaymentMethodToggleComponent,
|
||||||
|
decorators: [
|
||||||
|
(Story: React.ComponentType) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
import PostalCodeComponent from '../../../../js/features/subscription/components/new/checkout/postal-code'
|
||||||
|
|
||||||
|
type Args = Pick<
|
||||||
|
React.ComponentProps<typeof PostalCodeComponent>,
|
||||||
|
'errorFields'
|
||||||
|
>
|
||||||
|
|
||||||
|
const Template = ({ errorFields }: Args) => {
|
||||||
|
const [value, setValue] = useState('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PostalCodeComponent
|
||||||
|
errorFields={errorFields}
|
||||||
|
value={value}
|
||||||
|
onChange={e => 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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import PriceSwitchHeaderComponent from '../../../../js/features/subscription/components/new/checkout/price-switch-header'
|
||||||
|
|
||||||
|
type Args = React.ComponentProps<typeof PriceSwitchHeaderComponent>
|
||||||
|
|
||||||
|
export const PriceSwitchHeader = (args: Args) => (
|
||||||
|
<PriceSwitchHeaderComponent {...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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import SubmitButtonComponent from '../../../../js/features/subscription/components/new/checkout/submit-button'
|
||||||
|
|
||||||
|
type Args = React.ComponentProps<typeof SubmitButtonComponent>
|
||||||
|
|
||||||
|
const Template = (args: Args) => <SubmitButtonComponent {...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) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import TosAgreementNoticeComponent from '../../../../js/features/subscription/components/new/checkout/tos-agreement-notice'
|
||||||
|
|
||||||
|
export const TosAgreementNotice = () => <TosAgreementNoticeComponent />
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Subscription / New / Checkout',
|
||||||
|
decorators: [
|
||||||
|
(Story: React.ComponentType) => (
|
||||||
|
<div
|
||||||
|
className="card card-highlighted card-border"
|
||||||
|
style={{ maxWidth: '500px' }}
|
||||||
|
>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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 (
|
||||||
|
<PaymentContext.Provider value={value}>{children}</PaymentContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import CollaboratorsComponent from '../../../../js/features/subscription/components/new/payment-preview/collaborators'
|
||||||
|
|
||||||
|
type Args = React.ComponentProps<typeof CollaboratorsComponent>
|
||||||
|
|
||||||
|
export const Collaborators = (args: Args) => (
|
||||||
|
<CollaboratorsComponent {...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) => (
|
||||||
|
<div style={{ maxWidth: '300px' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<typeof FeaturesListComponent>
|
||||||
|
|
||||||
|
export const FeaturesList = (args: Args) => <FeaturesListComponent {...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) => (
|
||||||
|
<div style={{ maxWidth: '300px' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<React.ComponentProps<typeof PaymentProvider>, 'value'>
|
||||||
|
|
||||||
|
const Template = (args: Args) => {
|
||||||
|
return (
|
||||||
|
<PaymentProvider value={args.value}>
|
||||||
|
<NoDiscountPriceComponent />
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => (
|
||||||
|
<div style={{ maxWidth: '300px' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<React.ComponentProps<typeof PaymentProvider>, 'value'>
|
||||||
|
|
||||||
|
const Template = (args: Args) => {
|
||||||
|
return (
|
||||||
|
<PaymentProvider value={args.value}>
|
||||||
|
<PriceForFirstXPeriod />
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => (
|
||||||
|
<div style={{ maxWidth: '300px' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<React.ComponentProps<typeof PaymentProvider>, 'value'>
|
||||||
|
|
||||||
|
export const PriceSummary = (args: Args) => {
|
||||||
|
return (
|
||||||
|
<PaymentProvider value={args.value}>
|
||||||
|
<PriceSummaryComponent />
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => (
|
||||||
|
<div style={{ maxWidth: '300px' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -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<React.ComponentProps<typeof PaymentProvider>, 'value'>
|
||||||
|
|
||||||
|
export const TrialPrice = (args: Args) => {
|
||||||
|
return (
|
||||||
|
<PaymentProvider value={args.value}>
|
||||||
|
<TrialPriceComponent />
|
||||||
|
</PaymentProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Subscription / New / Payment Preview',
|
||||||
|
component: TrialPriceComponent,
|
||||||
|
args: {
|
||||||
|
value: {
|
||||||
|
currencySymbol: '$',
|
||||||
|
recurlyPrice: {
|
||||||
|
total: '10.00',
|
||||||
|
},
|
||||||
|
trialLength: 7,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story: React.ComponentType) => (
|
||||||
|
<div style={{ maxWidth: '300px' }}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
Loading…
Reference in a new issue