mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -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 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 (
|
||||
|
|
|
@ -333,7 +333,9 @@ function usePayment({ publicKey }: RecurlyOptions) {
|
|||
return { value }
|
||||
}
|
||||
|
||||
const PaymentContext = createContext<PaymentContextValue | undefined>(undefined)
|
||||
export const PaymentContext = createContext<PaymentContextValue | undefined>(
|
||||
undefined
|
||||
)
|
||||
|
||||
type PaymentProviderProps = {
|
||||
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