Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/chatty-maps-shine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/ui': patch
---

Add `ProfileCard.Page` for `UserProfile` and `OrganizationProfile` pages
23 changes: 13 additions & 10 deletions packages/ui/src/common/CustomPageContentContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { Col, descriptors } from '../customizables';
import { ProfileCard } from '../elements/ProfileCard';
import type { CustomPageContent } from '../utils/createCustomPages';
import { ExternalElementMounter } from '../utils/ExternalElementMounter';

export const CustomPageContentContainer = ({ mount, unmount }: Omit<CustomPageContent, 'url'>) => {
return (
<Col
elementDescriptor={descriptors.page}
gap={8}
>
<ProfileCard.Page>
<Col
elementDescriptor={descriptors.profilePage}
elementDescriptor={descriptors.page}
gap={8}
>
<ExternalElementMounter
mount={mount}
unmount={unmount}
/>
<Col
elementDescriptor={descriptors.profilePage}
gap={8}
>
<ExternalElementMounter
mount={mount}
unmount={unmount}
/>
</Col>
</Col>
</Col>
</ProfileCard.Page>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { APIKeysContext, useOrganizationProfileContext } from '@/ui/contexts';
import { Col, localizationKeys } from '@/ui/customizables';
import { Header } from '@/ui/elements/Header';
import { useUnsafeNavbarContext } from '@/ui/elements/Navbar';
import { ProfileCard } from '@/ui/elements/ProfileCard';

import { APIKeysPage } from '../APIKeys/APIKeys';

Expand All @@ -18,19 +19,21 @@ export const OrganizationAPIKeysPage = () => {
}

return (
<Col gap={4}>
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.apiKeysPage.title')}
textVariant='h2'
/>
</Header.Root>
<APIKeysContext.Provider value={{ ...apiKeysProps, componentName: 'APIKeys' }}>
<APIKeysPage
subject={organization.id}
revokeModalRoot={contentRef}
/>
</APIKeysContext.Provider>
</Col>
<ProfileCard.Page>
<Col gap={4}>
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.apiKeysPage.title')}
textVariant='h2'
/>
</Header.Root>
<APIKeysContext.Provider value={{ ...apiKeysProps, componentName: 'APIKeys' }}>
<APIKeysPage
subject={organization.id}
revokeModalRoot={contentRef}
/>
</APIKeysContext.Provider>
</Col>
</ProfileCard.Page>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Card } from '@/ui/elements/Card';
import { useCardState, withCardStateProvider } from '@/ui/elements/contexts';
import { Header } from '@/ui/elements/Header';
import { ProfileCard } from '@/ui/elements/ProfileCard';
import { Tab, TabPanel, TabPanels, Tabs, TabsList } from '@/ui/elements/Tabs';

import { Protect } from '../../common';
Expand All @@ -24,63 +25,67 @@ const OrganizationBillingPageInternal = withCardStateProvider(() => {
const { selectedTab, handleTabChange } = useTabState(orgTabMap);

return (
<Col
elementDescriptor={descriptors.page}
sx={t => ({ gap: t.space.$8, color: t.colors.$colorForeground })}
>
<ProfileCard.Page>
<Col
elementDescriptor={descriptors.profilePage}
elementId={descriptors.profilePage.setId('billing')}
gap={4}
elementDescriptor={descriptors.page}
sx={t => ({ gap: t.space.$8, color: t.colors.$colorForeground })}
>
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.billingPage.title')}
textVariant='h2'
/>
</Header.Root>

<Card.Alert>{card.error}</Card.Alert>

<Tabs
value={selectedTab}
onChange={handleTabChange}
<Col
elementDescriptor={descriptors.profilePage}
elementId={descriptors.profilePage.setId('billing')}
gap={4}
>
<TabsList sx={t => ({ gap: t.space.$6 })}>
<Tab
localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__subscriptions')}
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.billingPage.title')}
textVariant='h2'
/>
<Tab localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__statements')} />
<Tab localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__payments')} />
</TabsList>
<TabPanels>
<TabPanel sx={{ width: '100%', flexDirection: 'column' }}>
<SubscriptionsList
title={localizationKeys('organizationProfile.billingPage.subscriptionsListSection.title')}
switchPlansLabel={localizationKeys(
'organizationProfile.billingPage.subscriptionsListSection.actionLabel__switchPlan',
)}
newSubscriptionLabel={localizationKeys(
'organizationProfile.billingPage.subscriptionsListSection.actionLabel__newSubscription',
)}
manageSubscriptionLabel={localizationKeys(
'organizationProfile.billingPage.subscriptionsListSection.actionLabel__manageSubscription',
)}
</Header.Root>

<Card.Alert>{card.error}</Card.Alert>

<Tabs
value={selectedTab}
onChange={handleTabChange}
>
<TabsList sx={t => ({ gap: t.space.$6 })}>
<Tab
localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__subscriptions')}
/>
<Tab
localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__statements')}
/>
<Protect condition={has => has({ permission: 'org:sys_billing:manage' })}>
<PaymentMethods />
</Protect>
</TabPanel>
<TabPanel sx={{ width: '100%' }}>
<StatementsList />
</TabPanel>
<TabPanel sx={{ width: '100%' }}>
<PaymentAttemptsList />
</TabPanel>
</TabPanels>
</Tabs>
<Tab localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__payments')} />
</TabsList>
<TabPanels>
<TabPanel sx={{ width: '100%', flexDirection: 'column' }}>
<SubscriptionsList
title={localizationKeys('organizationProfile.billingPage.subscriptionsListSection.title')}
switchPlansLabel={localizationKeys(
'organizationProfile.billingPage.subscriptionsListSection.actionLabel__switchPlan',
)}
newSubscriptionLabel={localizationKeys(
'organizationProfile.billingPage.subscriptionsListSection.actionLabel__newSubscription',
)}
manageSubscriptionLabel={localizationKeys(
'organizationProfile.billingPage.subscriptionsListSection.actionLabel__manageSubscription',
)}
/>
<Protect condition={has => has({ permission: 'org:sys_billing:manage' })}>
<PaymentMethods />
</Protect>
</TabPanel>
<TabPanel sx={{ width: '100%' }}>
<StatementsList />
</TabPanel>
<TabPanel sx={{ width: '100%' }}>
<PaymentAttemptsList />
</TabPanel>
</TabPanels>
</Tabs>
</Col>
</Col>
</Col>
</ProfileCard.Page>
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useOrganization } from '@clerk/shared/react';

import { Header } from '@/ui/elements/Header';
import { OrganizationPreview } from '@/ui/elements/OrganizationPreview';
import { ProfileCard } from '@/ui/elements/ProfileCard';
import { ProfileSection } from '@/ui/elements/Section';

import { Protect, useProtect } from '../../common';
Expand Down Expand Up @@ -56,29 +57,31 @@ const DeleteOrganizationScreen = () => {

export const OrganizationGeneralPage = () => {
return (
<Col
elementDescriptor={descriptors.page}
sx={t => ({ gap: t.space.$8 })}
>
<ProfileCard.Page>
<Col
elementDescriptor={descriptors.profilePage}
elementId={descriptors.profilePage.setId('organizationGeneral')}
elementDescriptor={descriptors.page}
sx={t => ({ gap: t.space.$8 })}
>
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.start.headerTitle__general')}
sx={t => ({ marginBottom: t.space.$4 })}
textVariant='h2'
/>
</Header.Root>
<OrganizationProfileSection />
<Protect permission='org:sys_domains:read'>
<OrganizationDomainsSection />
</Protect>
<OrganizationLeaveSection />
<OrganizationDeleteSection />
<Col
elementDescriptor={descriptors.profilePage}
elementId={descriptors.profilePage.setId('organizationGeneral')}
>
<Header.Root>
<Header.Title
localizationKey={localizationKeys('organizationProfile.start.headerTitle__general')}
sx={t => ({ marginBottom: t.space.$4 })}
textVariant='h2'
/>
</Header.Root>
<OrganizationProfileSection />
<Protect permission='org:sys_domains:read'>
<OrganizationDomainsSection />
</Protect>
<OrganizationLeaveSection />
<OrganizationDeleteSection />
</Col>
</Col>
</Col>
</ProfileCard.Page>
);
};

Expand Down
Loading
Loading