Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 470
feat(clerk-js,types,clerk-react): Add internal open/close checkout methods#5481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
dfe84ea44d8879c22a3218acac44bb4212b41fd1a0e9e59d75c280680151de02b31f6e1e2e028f779ac71608130d29bf85File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| '@clerk/clerk-js': patch | ||
| '@clerk/clerk-react': patch | ||
| '@clerk/types': patch | ||
| --- | ||
| Introduce `clerk.__internal_openCheckout()` and `clerk.__internal_closeCheckout()` methods and remove `<Checkout />` from within the `<PricingTable />` component. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,43 +1,25 @@ | ||
| import type { __experimental_CheckoutProps } from '@clerk/types'; | ||
| import { PROFILE_CARD_SCROLLBOX_ID } from '../../constants'; | ||
| import { useCheckoutContext, withCoreUserGuard } from '../../contexts'; | ||
| import { __experimental_CheckoutContext } from '../../contexts'; | ||
| import { Flow } from '../../customizables'; | ||
| import { Drawer } from '../../elements'; | ||
| import { Route, Switch } from '../../router'; | ||
| import { CheckoutPage } from './CheckoutPage'; | ||
| export const __experimental_Checkout = (props: __experimental_CheckoutProps) => { | ||
| return ( | ||
| <Flow.Root flow='checkout'> | ||
| <Flow.Part> | ||
| <Switch> | ||
| <Route> | ||
| <AuthenticatedRoutes {...props} /> | ||
| </Route> | ||
| </Switch> | ||
| <__experimental_CheckoutContext.Provider | ||
| value={{ | ||
| componentName: 'Checkout', | ||
| }} | ||
| > | ||
| <Drawer.Content> | ||
| <Drawer.Header title='Checkout' /> | ||
| <CheckoutPage {...props} /> | ||
| </Drawer.Content> | ||
| </__experimental_CheckoutContext.Provider> | ||
| </Flow.Part> | ||
| </Flow.Root> | ||
| ); | ||
| }; | ||
| const AuthenticatedRoutes = withCoreUserGuard((props: __experimental_CheckoutProps) => { | ||
| const { mode = 'mounted', isOpen = false, setIsOpen = () => {} } = useCheckoutContext(); | ||
| return ( | ||
| <Drawer.Root | ||
| open={isOpen} | ||
| onOpenChange={setIsOpen} | ||
| strategy={mode === 'mounted' ? 'fixed' : 'absolute'} | ||
| portalProps={{ | ||
| id: mode === 'modal' ? PROFILE_CARD_SCROLLBOX_ID : undefined, | ||
| }} | ||
| > | ||
| <Drawer.Overlay /> | ||
| <Drawer.Content> | ||
| <Drawer.Header title='Checkout' /> | ||
| <CheckoutPage {...props} /> | ||
| </Drawer.Content> | ||
| </Drawer.Root> | ||
| ); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8,10 +8,9 @@ import type { | ||
| import { useState } from 'react'; | ||
| import { PROFILE_CARD_SCROLLBOX_ID } from '../../constants'; | ||
| import { __experimental_CheckoutContext, usePricingTableContext } from '../../contexts'; | ||
| import { usePricingTableContext } from '../../contexts'; | ||
| import { AppearanceProvider } from '../../customizables'; | ||
| import { usePlans } from '../../hooks'; | ||
| import { __experimental_Checkout } from '../Checkout'; | ||
| import { PricingTableDefault } from './PricingTableDefault'; | ||
| import { PricingTableMatrix } from './PricingTableMatrix'; | ||
| import { SubscriptionDetailDrawer } from './SubscriptionDetailDrawer'; | ||
| @@ -25,10 +24,8 @@ export const __experimental_PricingTable = (props: __experimental_PricingTablePr | ||
| const { plans, subscriptions, revalidate } = usePlans({ subscriberType }); | ||
| const [planPeriod, setPlanPeriod] = useState<__experimental_CommerceSubscriptionPlanPeriod>('month'); | ||
| const [checkoutPlan, setCheckoutPlan] = useState<__experimental_CommercePlanResource>(); | ||
| const [detailSubscription, setDetailSubscription] = useState<__experimental_CommerceSubscriptionResource>(); | ||
| const [showCheckout, setShowCheckout] = useState(false); | ||
| const [showSubscriptionDetailDrawer, setShowSubscriptionDetailDrawer] = useState(false); | ||
| const selectPlan = (plan: __experimental_CommercePlanResource) => { | ||
| @@ -40,8 +37,13 @@ export const __experimental_PricingTable = (props: __experimental_PricingTablePr | ||
| setDetailSubscription(activeSubscription); | ||
| setShowSubscriptionDetailDrawer(true); | ||
| } else { | ||
| setCheckoutPlan(plan); | ||
| setShowCheckout(true); | ||
| clerk.__internal_openCheckout({ | ||
| planId: plan.id, | ||
| planPeriod, | ||
| orgId: subscriberType === 'org' ? organization?.id : undefined, | ||
| onSubscriptionComplete: onSubscriptionChange, | ||
| portalId: mode === 'modal' ? PROFILE_CARD_SCROLLBOX_ID : undefined, | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does As a semi-related nit, I might rename MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mode is set on the PricingTable and I think was originally adding following the other components, but there is no modal mode for PricingTable, so yeah, it is confusing, as its only a mounted component. Will refactor naming approach in a follow up PR.
Comment on lines
+40
to
+45
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is much cleaner! | ||
| }); | ||
| } | ||
| }; | ||
| @@ -74,26 +76,6 @@ export const __experimental_PricingTable = (props: __experimental_PricingTablePr | ||
| appearanceKey='checkout' | ||
| appearance={props.checkoutProps?.appearance} | ||
| > | ||
| <__experimental_CheckoutContext.Provider | ||
| value={{ | ||
| componentName: 'Checkout', | ||
| mode, | ||
| isOpen: showCheckout, | ||
| setIsOpen: setShowCheckout, | ||
| }} | ||
| > | ||
| {/*TODO: Used by InvisibleRootBox, can we simplify? */} | ||
| <div> | ||
| {checkoutPlan && ( | ||
| <__experimental_Checkout | ||
| planPeriod={planPeriod} | ||
| planId={checkoutPlan.id} | ||
| orgId={subscriberType === 'org' ? organization?.id : undefined} | ||
| onSubscriptionComplete={onSubscriptionChange} | ||
| /> | ||
| )} | ||
| </div> | ||
| </__experimental_CheckoutContext.Provider> | ||
| <SubscriptionDetailDrawer | ||
| isOpen={showSubscriptionDetailDrawer} | ||
| setIsOpen={setShowSubscriptionDetailDrawer} | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introducing new drawer specific methods as we want to have an exit animation for the drawers, and removing all the props causes issues with portaling into the profile components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to consolidate the modal/drawer handling at some point in the future. I would expect them to function the same, just be a different flavor of UI. Maybe there's a good reason to keep them separate though? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want modals to have an exit animation, we'd need to follow this updated drawer pattern, currently all modals are removed immediately but wiping out the props.