Skip to content

Commit 54d5f93

Browse files
authored
Merge branch 'main' into vaggelis/com-763-cant-switch-to-monthly-subscription-for-the-same-plan-if
2 parents 06067d2 + 320937a commit 54d5f93

File tree

13 files changed

+142
-72
lines changed

13 files changed

+142
-72
lines changed

.changeset/chubby-memes-pull.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/localizations': patch
3+
'@clerk/clerk-js': patch
4+
---
5+
6+
Added a notice in tooltip when member no has permissions to manage billing for all manager related buttons

.changeset/rude-friends-create.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Fix mobile `<Drawer />` sizing.

.changeset/smart-horses-wish.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
'@clerk/types': patch
4+
---
5+
6+
Add descriptor ids to `UserMembershipList` and `OrganizationSwitcherTrigger` elements to improve styling experience.

.changeset/two-keys-act.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Add loading state to `<PaymentSources />` component.

packages/clerk-js/src/ui/components/OrganizationSwitcher/OrganizationSwitcherTrigger.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const OrganizationSwitcherTrigger = withAvatarShimmer(
3030
return (
3131
<Button
3232
elementDescriptor={descriptors.organizationSwitcherTrigger}
33+
elementId={descriptors.organizationSwitcherTrigger.setId(organization ? 'organization' : 'personal')}
3334
variant='ghost'
3435
colorScheme='neutral'
3536
hoverAsFocus

packages/clerk-js/src/ui/components/OrganizationSwitcher/UserMembershipList.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export const UserMembershipList = (props: UserMembershipListProps) => {
7777
{currentOrg && !hidePersonal && (
7878
<PreviewButton
7979
elementDescriptor={descriptors.organizationSwitcherPreviewButton}
80+
elementId={descriptors.organizationSwitcherPreviewButton.setId('personal')}
8081
icon={SwitchArrowRight}
8182
onClick={onPersonalWorkspaceClick}
8283
role='menuitem'
@@ -92,6 +93,7 @@ export const UserMembershipList = (props: UserMembershipListProps) => {
9293
<PreviewButton
9394
key={organization.id}
9495
elementDescriptor={descriptors.organizationSwitcherPreviewButton}
96+
elementId={descriptors.organizationSwitcherPreviewButton.setId('organization')}
9597
icon={SwitchArrowRight}
9698
onClick={() => onOrganizationClick(organization)}
9799
role='menuitem'

packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Fragment, useMemo, useRef } from 'react';
66
import { RemoveResourceForm } from '../../common';
77
import { useSubscriberTypeContext } from '../../contexts';
88
import { localizationKeys } from '../../customizables';
9-
import { ProfileSection, ThreeDotsMenu, useCardState } from '../../elements';
9+
import { FullHeightLoader, ProfileSection, ThreeDotsMenu, useCardState, withCardStateProvider } from '../../elements';
1010
import { Action } from '../../elements/Action';
1111
import { useActionContext } from '../../elements/Action/ActionRoot';
1212
import { useFetch } from '../../hooks';
@@ -83,25 +83,29 @@ const RemoveScreen = ({
8383
);
8484
};
8585

86-
export const PaymentSources = () => {
86+
export const PaymentSources = withCardStateProvider(() => {
8787
const clerk = useClerk();
8888
const subscriberType = useSubscriberTypeContext();
8989

9090
const resource = subscriberType === 'org' ? clerk?.organization : clerk.user;
9191

92-
const { data, revalidate } = useFetch(
92+
const { data, revalidate, isLoading } = useFetch(
9393
resource?.getPaymentSources,
9494
{},
9595
undefined,
9696
`commerce-payment-sources-${resource?.id}`,
9797
);
98-
const { data: paymentSources } = data || { data: [] };
98+
const { data: paymentSources = [] } = data || {};
9999

100100
const sortedPaymentSources = useMemo(
101101
() => paymentSources.sort((a, b) => (a.isDefault && !b.isDefault ? -1 : 1)),
102102
[paymentSources],
103103
);
104104

105+
if (!resource) {
106+
return null;
107+
}
108+
105109
return (
106110
<ProfileSection.Root
107111
title={localizationKeys('userProfile.billingPage.paymentSourcesSection.title')}
@@ -115,43 +119,52 @@ export const PaymentSources = () => {
115119
})}
116120
>
117121
<Action.Root>
118-
<ProfileSection.ItemList id='paymentSources'>
119-
{sortedPaymentSources.map(paymentSource => (
120-
<Fragment key={paymentSource.id}>
121-
<ProfileSection.Item id='paymentSources'>
122-
<PaymentSourceRow paymentSource={paymentSource} />
123-
<PaymentSourceMenu
124-
paymentSource={paymentSource}
125-
revalidate={revalidate}
122+
<ProfileSection.ItemList
123+
id='paymentSources'
124+
disableAnimation
125+
>
126+
{isLoading ? (
127+
<FullHeightLoader />
128+
) : (
129+
<>
130+
{sortedPaymentSources.map(paymentSource => (
131+
<Fragment key={paymentSource.id}>
132+
<ProfileSection.Item id='paymentSources'>
133+
<PaymentSourceRow paymentSource={paymentSource} />
134+
<PaymentSourceMenu
135+
paymentSource={paymentSource}
136+
revalidate={revalidate}
137+
/>
138+
</ProfileSection.Item>
139+
140+
<Action.Open value={`remove-${paymentSource.id}`}>
141+
<Action.Card variant='destructive'>
142+
<RemoveScreen
143+
paymentSource={paymentSource}
144+
revalidate={revalidate}
145+
/>
146+
</Action.Card>
147+
</Action.Open>
148+
</Fragment>
149+
))}
150+
<Action.Trigger value='add'>
151+
<ProfileSection.ArrowButton
152+
id='paymentSources'
153+
localizationKey={localizationKeys('userProfile.billingPage.paymentSourcesSection.add')}
126154
/>
127-
</ProfileSection.Item>
128-
129-
<Action.Open value={`remove-${paymentSource.id}`}>
130-
<Action.Card variant='destructive'>
131-
<RemoveScreen
132-
paymentSource={paymentSource}
133-
revalidate={revalidate}
134-
/>
155+
</Action.Trigger>
156+
<Action.Open value='add'>
157+
<Action.Card>
158+
<AddScreen onSuccess={revalidate} />
135159
</Action.Card>
136160
</Action.Open>
137-
</Fragment>
138-
))}
139-
<Action.Trigger value='add'>
140-
<ProfileSection.ArrowButton
141-
id='paymentSources'
142-
localizationKey={localizationKeys('userProfile.billingPage.paymentSourcesSection.add')}
143-
/>
144-
</Action.Trigger>
145-
<Action.Open value='add'>
146-
<Action.Card>
147-
<AddScreen onSuccess={revalidate} />
148-
</Action.Card>
149-
</Action.Open>
161+
</>
162+
)}
150163
</ProfileSection.ItemList>
151164
</Action.Root>
152165
</ProfileSection.Root>
153166
);
154-
};
167+
});
155168

156169
const PaymentSourceMenu = ({
157170
paymentSource,

packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useClerk } from '@clerk/shared/react';
1+
import { useClerk, useSession } from '@clerk/shared/react';
22
import type { CommercePlanResource, CommerceSubscriptionPlanPeriod, PricingTableProps } from '@clerk/types';
33
import * as React from 'react';
44

5+
import { useProtect } from '../../common';
56
import { usePlansContext, usePricingTableContext, useSubscriberTypeContext } from '../../contexts';
67
import {
78
Badge,
@@ -17,7 +18,7 @@ import {
1718
Span,
1819
Text,
1920
} from '../../customizables';
20-
import { Switch } from '../../elements';
21+
import { Switch, Tooltip } from '../../elements';
2122
import { Check, Plus } from '../../icons';
2223
import { common, InternalThemeProvider } from '../../styledSystem';
2324
import { colors, getClosestProfileScrollBox } from '../../utils';
@@ -97,13 +98,17 @@ interface CardProps {
9798
function Card(props: CardProps) {
9899
const { plan, planPeriod, setPlanPeriod, onSelect, props: pricingTableProps, isCompact = false } = props;
99100
const clerk = useClerk();
101+
const { isSignedIn } = useSession();
100102
const { mode = 'mounted', ctaPosition: ctxCtaPosition } = usePricingTableContext();
101103
const subscriberType = useSubscriberTypeContext();
102104

103105
const ctaPosition = pricingTableProps.ctaPosition || ctxCtaPosition || 'bottom';
104106
const collapseFeatures = pricingTableProps.collapseFeatures || false;
105107
const { id, slug } = plan;
106108

109+
const canManageBilling = useProtect(
110+
has => has({ permission: 'org:sys_billing:manage' }) || subscriberType === 'user',
111+
);
107112
const { buttonPropsForPlan, upcomingSubscriptionsExist, activeOrUpcomingSubscriptionBasedOnPlanPeriod } =
108113
usePlansContext();
109114

@@ -244,15 +249,24 @@ function Card(props: CardProps) {
244249
})}
245250
/>
246251
) : (
247-
<Button
248-
elementDescriptor={descriptors.pricingTableCardFooterButton}
249-
block
250-
textVariant={isCompact ? 'buttonSmall' : 'buttonLarge'}
251-
{...buttonPropsForPlan({ plan, isCompact, selectedPlanPeriod: planPeriod })}
252-
onClick={event => {
253-
onSelect(plan, event);
254-
}}
255-
/>
252+
<Tooltip.Root>
253+
<Tooltip.Trigger sx={{ width: '100%' }}>
254+
<Button
255+
elementDescriptor={descriptors.pricingTableCardFooterButton}
256+
block
257+
textVariant={isCompact ? 'buttonSmall' : 'buttonLarge'}
258+
{...buttonPropsForPlan({ plan, isCompact, selectedPlanPeriod: planPeriod })}
259+
onClick={event => {
260+
onSelect(plan, event);
261+
}}
262+
/>
263+
</Tooltip.Trigger>
264+
{isSignedIn && !canManageBilling && (
265+
<Tooltip.Content
266+
text={localizationKeys('organizationProfile.billingPage.alerts.noPermissionsToManageBilling')}
267+
/>
268+
)}
269+
</Tooltip.Root>
256270
)}
257271
</Box>
258272
) : (

packages/clerk-js/src/ui/contexts/components/Plans.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ export const usePlansContext = () => {
244244
variant: 'bordered' | 'solid';
245245
colorScheme: 'secondary' | 'primary';
246246
isDisabled: boolean;
247+
disabled: boolean;
247248
} => {
248249
const subscription =
249250
sub ?? (plan ? activeOrUpcomingSubscriptionWithPlanPeriod(plan, selectedPlanPeriod) : undefined);
@@ -299,6 +300,7 @@ export const usePlansContext = () => {
299300
variant: isCompact ? 'bordered' : 'solid',
300301
colorScheme: isCompact ? 'secondary' : 'primary',
301302
isDisabled: !canManageBilling,
303+
disabled: !canManageBilling,
302304
};
303305
},
304306
[activeOrUpcomingSubscriptionWithPlanPeriod, canManageBilling, ctx.subscriptions],

packages/clerk-js/src/ui/elements/Drawer.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ function Root({
9292
onOpenChange,
9393
transform: false,
9494
strategy,
95+
placement: 'right',
9596
...floatingProps,
9697
});
9798

@@ -223,7 +224,8 @@ const Content = React.forwardRef<HTMLDivElement, ContentProps>(({ children }, re
223224
style={{
224225
position: strategy,
225226
insetBlock: 0,
226-
insetInlineEnd: 0,
227+
insetInline: 0,
228+
pointerEvents: 'none',
227229
}}
228230
>
229231
<Flex
@@ -241,17 +243,19 @@ const Content = React.forwardRef<HTMLDivElement, ContentProps>(({ children }, re
241243
insetInlineEnd: strategy === 'fixed' ? t.space.$3 : 0,
242244
outline: 0,
243245
width: t.sizes.$100,
246+
maxWidth: strategy === 'fixed' ? `calc(100% - ${t.space.$6})` : '100%',
244247
backgroundColor: t.colors.$colorBackground,
245-
borderStartStartRadius: t.radii.$xl,
246-
borderEndStartRadius: t.radii.$xl,
247-
borderEndEndRadius: strategy === 'fixed' ? t.radii.$xl : 0,
248-
borderStartEndRadius: strategy === 'fixed' ? t.radii.$xl : 0,
248+
borderStartStartRadius: t.radii.$lg,
249+
borderEndStartRadius: t.radii.$lg,
250+
borderEndEndRadius: strategy === 'fixed' ? t.radii.$lg : 0,
251+
borderStartEndRadius: strategy === 'fixed' ? t.radii.$lg : 0,
249252
borderWidth: t.borderWidths.$normal,
250253
borderStyle: t.borderStyles.$solid,
251254
borderColor: t.colors.$neutralAlpha100,
252255
boxShadow: t.shadows.$cardBoxShadow,
253256
overflow: 'hidden',
254257
zIndex: t.zIndices.$modal,
258+
pointerEvents: 'auto',
255259
})}
256260
>
257261
{children}
@@ -289,8 +293,8 @@ const Header = React.forwardRef<HTMLDivElement, HeaderProps>(({ title, children,
289293
borderBlockEndWidth: t.borderWidths.$normal,
290294
borderBlockEndStyle: t.borderStyles.$solid,
291295
borderBlockEndColor: t.colors.$neutralAlpha100,
292-
borderStartStartRadius: t.radii.$xl,
293-
borderStartEndRadius: t.radii.$xl,
296+
borderStartStartRadius: t.radii.$lg,
297+
borderStartEndRadius: t.radii.$lg,
294298
paddingBlock: title ? t.space.$3 : undefined,
295299
paddingInline: title ? t.space.$4 : undefined,
296300
}),

0 commit comments

Comments
 (0)