1- import type { OrganizationResource , UserOrganizationInvitationResource } from '@clerk/types ' ;
1+ import React from 'react ' ;
22
3- import { Plus , SwitchArrows } from '../../../ui/icons' ;
4- import {
5- useCoreOrganization ,
6- useCoreOrganizationList ,
7- useCoreUser ,
8- useOrganizationSwitcherContext ,
9- } from '../../contexts' ;
10- import { Box , Button , descriptors , Flex , localizationKeys , Spinner , Text } from '../../customizables' ;
11- import {
12- Action ,
13- OrganizationPreview ,
14- PersonalWorkspacePreview ,
15- PreviewButton ,
16- SecondaryActions ,
17- useCardState ,
18- withCardStateProvider ,
19- } from '../../elements' ;
20- import { useInView } from '../../hooks' ;
21- import { common } from '../../styledSystem' ;
22- import { handleError } from '../../utils' ;
3+ import { Plus } from '../../../ui/icons' ;
4+ import { useCoreUser } from '../../contexts' ;
5+ import { descriptors , localizationKeys } from '../../customizables' ;
6+ import { Action , SecondaryActions } from '../../elements' ;
7+ import { UserInvitationList } from './UserInvitationList' ;
8+ import type { UserMembershipListProps } from './UserMembershipList' ;
9+ import { UserMembershipList } from './UserMembershipList' ;
2310
24- type OrganizationActionListProps = {
11+ export interface OrganizationActionListProps extends UserMembershipListProps {
2512 onCreateOrganizationClick : React . MouseEventHandler ;
26- onPersonalWorkspaceClick : React . MouseEventHandler ;
27- onOrganizationClick : ( org : OrganizationResource ) => unknown ;
28- } ;
29-
30- export const OrganizationActionList = ( props : OrganizationActionListProps ) => {
31- const { onCreateOrganizationClick, onPersonalWorkspaceClick, onOrganizationClick } = props ;
32- const { organizationList, userInvitations } = useCoreOrganizationList ( {
33- userInvitations : {
34- infinite : true ,
35- } ,
36- } ) ;
37-
38- const { ref } = useInView ( {
39- threshold : 0 ,
40- onChange : inView => {
41- if ( inView ) {
42- userInvitations . fetchNext ?.( ) ;
43- }
44- } ,
45- } ) ;
13+ }
4614
47- const { organization : currentOrg } = useCoreOrganization ( ) ;
15+ const CreateOrganizationButton = ( {
16+ onCreateOrganizationClick,
17+ } : Pick < OrganizationActionListProps , 'onCreateOrganizationClick' > ) => {
4818 const user = useCoreUser ( ) ;
49- // eslint-disable-next-line @typescript-eslint/no-unused-vars
50- const { username, primaryEmailAddress, primaryPhoneNumber, ...userWithoutIdentifiers } = user ;
51- const { hidePersonal } = useOrganizationSwitcherContext ( ) ;
5219
53- const otherOrgs = ( organizationList || [ ] ) . map ( e => e . organization ) . filter ( o => o . id !== currentOrg ?. id ) ;
20+ if ( ! user . createOrganizationEnabled ) {
21+ return null ;
22+ }
5423
55- const createOrganizationButton = (
24+ return (
5625 < Action
5726 elementDescriptor = { descriptors . organizationSwitcherPopoverActionButton }
5827 elementId = { descriptors . organizationSwitcherPopoverActionButton . setId ( 'createOrganization' ) }
@@ -67,175 +36,16 @@ export const OrganizationActionList = (props: OrganizationActionListProps) => {
6736 onClick = { onCreateOrganizationClick }
6837 />
6938 ) ;
70-
71- return (
72- < SecondaryActions elementDescriptor = { descriptors . organizationSwitcherPopoverActions } >
73- < Box
74- sx = { t => ( {
75- maxHeight : `calc(4 * ${ t . sizes . $12 } )` ,
76- overflowY : 'auto' ,
77- ...common . unstyledScrollbar ( t ) ,
78- } ) }
79- >
80- { currentOrg && ! hidePersonal && (
81- < PreviewButton
82- elementDescriptor = { descriptors . organizationSwitcherPreviewButton }
83- icon = { SwitchArrows }
84- sx = { { borderRadius : 0 } }
85- onClick = { onPersonalWorkspaceClick }
86- >
87- < PersonalWorkspacePreview
88- user = { userWithoutIdentifiers }
89- size = 'sm'
90- avatarSx = { t => ( { margin : `0 calc(${ t . space . $3 } /2)` } ) }
91- title = { localizationKeys ( 'organizationSwitcher.personalWorkspace' ) }
92- />
93- </ PreviewButton >
94- ) }
95- { otherOrgs . map ( organization => (
96- < PreviewButton
97- key = { organization . id }
98- elementDescriptor = { descriptors . organizationSwitcherPreviewButton }
99- icon = { SwitchArrows }
100- sx = { { borderRadius : 0 } }
101- onClick = { ( ) => onOrganizationClick ( organization ) }
102- >
103- < OrganizationPreview
104- elementId = { 'organizationSwitcher' }
105- avatarSx = { t => ( { margin : `0 calc(${ t . space . $3 } /2)` } ) }
106- organization = { organization }
107- size = 'sm'
108- />
109- </ PreviewButton >
110- ) ) }
111- </ Box >
112-
113- { ( userInvitations . count ?? 0 ) > 0 && (
114- < Flex
115- direction = 'col'
116- elementDescriptor = { descriptors . organizationSwitcherPopoverInvitationActions }
117- >
118- < Text
119- variant = 'smallRegular'
120- sx = { t => ( {
121- minHeight : 'unset' ,
122- height : t . space . $12 ,
123- padding : `${ t . space . $3 } ${ t . space . $6 } ` ,
124- display : 'flex' ,
125- alignItems : 'center' ,
126- } ) }
127- // Handle plurals
128- localizationKey = { localizationKeys (
129- ( userInvitations . count ?? 0 ) > 1
130- ? 'organizationSwitcher.invitationCountLabel_many'
131- : 'organizationSwitcher.invitationCountLabel_single' ,
132- {
133- count : userInvitations . count ,
134- } ,
135- ) }
136- />
137- < Box
138- sx = { t => ( {
139- maxHeight : `calc(4 * ${ t . sizes . $12 } )` ,
140- overflowY : 'auto' ,
141- ...common . unstyledScrollbar ( t ) ,
142- } ) }
143- >
144- { userInvitations ?. data ?. map ( inv => {
145- return (
146- < InvitationPreview
147- key = { inv . id }
148- { ...inv }
149- />
150- ) ;
151- } ) }
152-
153- { ( userInvitations . hasNextPage || userInvitations . isFetching ) && (
154- < Box
155- ref = { ref }
156- sx = { t => ( {
157- width : '100%' ,
158- height : t . space . $12 ,
159- position : 'relative' ,
160- } ) }
161- >
162- < Box
163- sx = { {
164- margin : 'auto' ,
165- position : 'absolute' ,
166- left : '50%' ,
167- top : '50%' ,
168- transform : 'translateY(-50%) translateX(-50%)' ,
169- } }
170- >
171- < Spinner
172- size = 'md'
173- colorScheme = 'primary'
174- />
175- </ Box >
176- </ Box >
177- ) }
178- </ Box >
179- </ Flex >
180- ) }
181- { user . createOrganizationEnabled && createOrganizationButton }
182- </ SecondaryActions >
183- ) ;
18439} ;
18540
186- const AcceptRejectInvitationButtons = ( props : UserOrganizationInvitationResource ) => {
187- const card = useCardState ( ) ;
188- const { userInvitations } = useCoreOrganizationList ( {
189- userInvitations : {
190- infinite : true ,
191- } ,
192- } ) ;
193-
194- const mutateSwrState = ( ) => {
195- ( userInvitations as any ) ?. unstable__mutate ?.( ) ;
196- } ;
197-
198- const handleAccept = ( ) => {
199- return card
200- . runAsync ( props . accept ( ) )
201- . then ( mutateSwrState )
202- . catch ( err => handleError ( err , [ ] , card . setError ) ) ;
203- } ;
41+ export const OrganizationActionList = ( props : OrganizationActionListProps ) => {
42+ const { onCreateOrganizationClick, onPersonalWorkspaceClick, onOrganizationClick } = props ;
20443
20544 return (
206- < >
207- < Button
208- elementDescriptor = { descriptors . organizationSwitcherInvitationAcceptButton }
209- textVariant = 'buttonExtraSmallBold'
210- variant = { 'solid' }
211- isLoading = { card . isLoading }
212- onClick = { handleAccept }
213- localizationKey = { localizationKeys ( 'organizationSwitcher.invitationAccept' ) }
214- />
215- </ >
45+ < SecondaryActions elementDescriptor = { descriptors . organizationSwitcherPopoverActions } >
46+ < UserMembershipList { ...{ onPersonalWorkspaceClick, onOrganizationClick } } />
47+ < UserInvitationList />
48+ < CreateOrganizationButton { ...{ onCreateOrganizationClick } } />
49+ </ SecondaryActions >
21650 ) ;
21751} ;
218-
219- const InvitationPreview = withCardStateProvider ( ( props : UserOrganizationInvitationResource ) => {
220- return (
221- < Flex
222- align = 'center'
223- gap = { 2 }
224- sx = { t => ( {
225- minHeight : 'unset' ,
226- height : t . space . $12 ,
227- justifyContent : 'space-between' ,
228- padding : `0 ${ t . space . $6 } ` ,
229- } ) }
230- >
231- < OrganizationPreview
232- elementId = { 'organizationSwitcher' }
233- avatarSx = { t => ( { margin : `0 calc(${ t . space . $3 } /2)` } ) }
234- organization = { props . publicOrganizationData }
235- size = 'sm'
236- />
237-
238- < AcceptRejectInvitationButtons { ...props } />
239- </ Flex >
240- ) ;
241- } ) ;
0 commit comments