Skip to content

Commit

Permalink
feat(clerk-js): Use Gate in OrganizationSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
panteliselef committed Oct 10, 2023
1 parent 5a3995b commit e7daa5a
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 148 deletions.
5 changes: 5 additions & 0 deletions .changeset/tender-planets-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Replace role based check with permission based checks inside the OrganizationSettings component.
234 changes: 119 additions & 115 deletions packages/clerk-js/src/ui/components/OrganizationProfile/DomainList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { GetDomainsParams, OrganizationEnrollmentMode } from '@clerk/types'
import type { OrganizationDomainVerificationStatus } from '@clerk/types';
import React, { useMemo } from 'react';

import { withGate } from '../../common/Gate';
import { useCoreOrganization } from '../../contexts';
import { Box, Col, localizationKeys, Spinner } from '../../customizables';
import { ArrowBlockButton, BlockWithTrailingComponent, ThreeDotsMenu } from '../../elements';
Expand All @@ -20,136 +21,139 @@ type DomainListProps = GetDomainsParams & {
fallback?: React.ReactNode;
};

export const DomainList = (props: DomainListProps) => {
const { verificationStatus, enrollmentMode, redirectSubPath, fallback, ...rest } = props;
const { organization, membership, domains } = useCoreOrganization({
domains: {
infinite: true,
...rest,
},
});
export const DomainList = withGate(
(props: DomainListProps) => {
const { verificationStatus, enrollmentMode, redirectSubPath, fallback, ...rest } = props;
const { organization, domains } = useCoreOrganization({
domains: {
infinite: true,
...rest,
},
});

const { ref } = useInView({
threshold: 0,
onChange: inView => {
if (inView) {
void domains?.fetchNext?.();
const { ref } = useInView({
threshold: 0,
onChange: inView => {
if (inView) {
void domains?.fetchNext?.();
}
},
});
const { navigate } = useRouter();

const domainList = useMemo(() => {
if (!domains?.data) {
return [];
}
},
});
const { navigate } = useRouter();

const isAdmin = membership?.role === 'admin';
return domains.data.filter(d => {
let matchesStatus = true;
let matchesMode = true;
if (verificationStatus) {
matchesStatus = !!d.verification && d.verification.status === verificationStatus;
}
if (enrollmentMode) {
matchesMode = d.enrollmentMode === enrollmentMode;
}

const domainList = useMemo(() => {
if (!domains?.data) {
return [];
}
return matchesStatus && matchesMode;
});
}, [domains?.data]);

return domains.data.filter(d => {
let matchesStatus = true;
let matchesMode = true;
if (verificationStatus) {
matchesStatus = !!d.verification && d.verification.status === verificationStatus;
}
if (enrollmentMode) {
matchesMode = d.enrollmentMode === enrollmentMode;
}

return matchesStatus && matchesMode;
});
}, [domains?.data]);
if (!organization) {
return null;
}

if (!organization || !isAdmin) {
return null;
}
// TODO: Split this to smaller components
return (
<Col>
{domainList.length === 0 && !domains?.isLoading && fallback}
{domainList.map(d => {
if (!(d.verification && d.verification.status === 'verified')) {
return (
<BlockWithTrailingComponent
key={d.id}
sx={t => ({
'&:hover': {
backgroundColor: t.colors.$blackAlpha50,
},
padding: `${t.space.$none} ${t.space.$4}`,
minHeight: t.sizes.$10,
})}
badge={<EnrollmentBadge organizationDomain={d} />}
trailingComponent={
<ThreeDotsMenu
actions={[
{
label: localizationKeys(
'organizationProfile.profilePage.domainSection.unverifiedDomain_menuAction__verify',
),
onClick: () => navigate(`${redirectSubPath}${d.id}/verify`),
},
{
label: localizationKeys(
'organizationProfile.profilePage.domainSection.unverifiedDomain_menuAction__remove',
),
isDestructive: true,
onClick: () => navigate(`${redirectSubPath}${d.id}/remove`),
},
]}
/>
}
>
{d.name}
</BlockWithTrailingComponent>
);
}

// TODO: Split this to smaller components
return (
<Col>
{domainList.length === 0 && !domains?.isLoading && fallback}
{domainList.map(d => {
if (!(d.verification && d.verification.status === 'verified')) {
return (
<BlockWithTrailingComponent
<ArrowBlockButton
key={d.id}
variant='ghost'
colorScheme='neutral'
badge={!verificationStatus ? <EnrollmentBadge organizationDomain={d} /> : undefined}
sx={t => ({
'&:hover': {
backgroundColor: t.colors.$blackAlpha50,
},
padding: `${t.space.$none} ${t.space.$4}`,
padding: `${t.space.$3} ${t.space.$4}`,
minHeight: t.sizes.$10,
})}
badge={<EnrollmentBadge organizationDomain={d} />}
trailingComponent={
<ThreeDotsMenu
actions={[
{
label: localizationKeys(
'organizationProfile.profilePage.domainSection.unverifiedDomain_menuAction__verify',
),
onClick: () => navigate(`${redirectSubPath}${d.id}/verify`),
},
{
label: localizationKeys(
'organizationProfile.profilePage.domainSection.unverifiedDomain_menuAction__remove',
),
isDestructive: true,
onClick: () => navigate(`${redirectSubPath}${d.id}/remove`),
},
]}
/>
}
onClick={() => navigate(`${redirectSubPath}${d.id}`)}
>
{d.name}
</BlockWithTrailingComponent>
</ArrowBlockButton>
);
}

return (
<ArrowBlockButton
key={d.id}
variant='ghost'
colorScheme='neutral'
badge={!verificationStatus ? <EnrollmentBadge organizationDomain={d} /> : undefined}
sx={t => ({
padding: `${t.space.$3} ${t.space.$4}`,
minHeight: t.sizes.$10,
})}
onClick={() => navigate(`${redirectSubPath}${d.id}`)}
>
{d.name}
</ArrowBlockButton>
);
})}
{(domains?.hasNextPage || domains?.isFetching) && (
<Box
ref={domains?.isFetching ? undefined : ref}
sx={[
t => ({
width: '100%',
height: t.space.$10,
position: 'relative',
}),
]}
>
})}
{(domains?.hasNextPage || domains?.isFetching) && (
<Box
sx={{
display: 'flex',
margin: 'auto',
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translateY(-50%) translateX(-50%)',
}}
ref={domains?.isFetching ? undefined : ref}
sx={[
t => ({
width: '100%',
height: t.space.$10,
position: 'relative',
}),
]}
>
<Spinner
size='md'
colorScheme='primary'
/>
<Box
sx={{
display: 'flex',
margin: 'auto',
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translateY(-50%) translateX(-50%)',
}}
>
<Spinner
size='md'
colorScheme='primary'
/>
</Box>
</Box>
</Box>
)}
</Col>
);
};
)}
</Col>
);
},
{
permission: 'org:domains:manage',
},
);
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Gate } from '../../common/Gate';
import { ProfileCardContent } from '../../elements';
import { Route, Switch } from '../../router';
import type { PropsOfComponent } from '../../styledSystem';
Expand All @@ -20,24 +21,49 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
path='profile'
flowStart
>
<ProfileSettingsPage />
<Gate
permission={'org:profile:manage'}
redirectTo='../'
>
<ProfileSettingsPage />
</Gate>
</Route>
<Route
path='domain'
flowStart
>
<Switch>
<Route path=':id/verify'>
<VerifyDomainPage />
<Gate
permission={'org:domains:manage'}
redirectTo='../../'
>
<VerifyDomainPage />
</Gate>
</Route>
<Route path=':id/remove'>
<RemoveDomainPage />
<Gate
permission={'org:domains:delete'}
redirectTo='../../'
>
<RemoveDomainPage />
</Gate>
</Route>
<Route path=':id'>
<VerifiedDomainPage />
<Gate
permission={'org:domains:manage'}
redirectTo='../../'
>
<VerifiedDomainPage />
</Gate>
</Route>
<Route index>
<AddDomainPage />
<Gate
permission={'org:domains:manage'}
redirectTo='../'
>
<AddDomainPage />
</Gate>
</Route>
</Switch>
</Route>
Expand All @@ -51,7 +77,12 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
path='delete'
flowStart
>
<DeleteOrganizationPage />
<Gate
permission={'org:profile:delete'}
redirectTo='../'
>
<DeleteOrganizationPage />
</Gate>
</Route>
<Route index>
<OrganizationSettings />
Expand All @@ -64,7 +95,12 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
path='invite-members'
flowStart
>
<InviteMembersPage />
<Gate
permission={'org:memberships:manage'}
redirectTo='../'
>
<InviteMembersPage />
</Gate>
</Route>
<Route index>
<OrganizationMembers />
Expand Down
Loading

0 comments on commit e7daa5a

Please sign in to comment.