Skip to content

Commit 42d58e6

Browse files
ChannelListItem related fixes
1 parent 6e0a3b3 commit 42d58e6

2 files changed

Lines changed: 163 additions & 176 deletions

File tree

src/components/ChannelListItem/ChannelListItemActionButtons.defaults.tsx

Lines changed: 161 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -145,82 +145,9 @@ type ChannelActionItem =
145145
Component: React.ComponentType<ComponentPropsWithRef<'button'>>;
146146
};
147147

148-
export const defaultChannelActionSet: ChannelActionItem[] = [
149-
{
150-
// eslint-disable-next-line react/display-name
151-
Component: forwardRef<HTMLButtonElement>((_, ref) => {
152-
const { channel } = useChannelListItemContext();
153-
154-
const dialogId = ChannelListItemActionButtons.getDialogId({
155-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
156-
channelId: channel.id!,
157-
});
158-
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });
159-
const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);
160-
161-
return (
162-
<Button
163-
appearance='ghost'
164-
aria-expanded={dialogIsOpen}
165-
aria-pressed={dialogIsOpen}
166-
circular
167-
onClick={(e) => {
168-
e.stopPropagation();
169-
170-
dialog.toggle();
171-
}}
172-
ref={ref}
173-
size='sm'
174-
variant='secondary'
175-
>
176-
<IconMore />
177-
</Button>
178-
);
179-
}),
180-
placement: 'quick-dropdown-toggle',
181-
},
182-
{
183-
Component() {
184-
const behaviorProps = useArchiveActionButtonBehavior();
185-
186-
return (
187-
<Button
188-
appearance='ghost'
189-
aria-label={behaviorProps.title}
190-
circular
191-
size='sm'
192-
variant='secondary'
193-
{...behaviorProps}
194-
>
195-
<IconArchive />
196-
</Button>
197-
);
198-
},
199-
placement: 'quick',
200-
type: 'archive',
201-
},
202-
{
203-
Component() {
204-
const behaviorProps = useMuteActionButtonBehavior();
205-
206-
return (
207-
<Button
208-
appearance='ghost'
209-
aria-label={behaviorProps.title}
210-
circular
211-
size='sm'
212-
variant='secondary'
213-
{...behaviorProps}
214-
>
215-
<IconMute />
216-
</Button>
217-
);
218-
},
219-
placement: 'quick',
220-
type: 'mute',
221-
},
222-
{
223-
Component() {
148+
const defaultComponents = {
149+
dropdown: {
150+
Archive() {
224151
const behaviorProps = useArchiveActionButtonBehavior();
225152

226153
return (
@@ -233,28 +160,7 @@ export const defaultChannelActionSet: ChannelActionItem[] = [
233160
</ContextMenuButton>
234161
);
235162
},
236-
placement: 'dropdown',
237-
type: 'archive',
238-
},
239-
{
240-
Component() {
241-
const behaviorProps = useMuteActionButtonBehavior();
242-
243-
return (
244-
<ContextMenuButton
245-
aria-label={behaviorProps.title}
246-
Icon={IconMute}
247-
{...behaviorProps}
248-
>
249-
{behaviorProps.title}
250-
</ContextMenuButton>
251-
);
252-
},
253-
placement: 'dropdown',
254-
type: 'mute',
255-
},
256-
{
257-
Component() {
163+
Ban() {
258164
const { client } = useChatContext();
259165
const { addNotification } = useNotificationApi();
260166
const { t } = useTranslationContext();
@@ -326,11 +232,72 @@ export const defaultChannelActionSet: ChannelActionItem[] = [
326232
</ContextMenuButton>
327233
);
328234
},
329-
placement: 'dropdown',
330-
type: 'ban',
331-
},
332-
{
333-
Component() {
235+
Leave() {
236+
const { t } = useTranslationContext();
237+
const { channel } = useChannelListItemContext();
238+
const { client } = useChatContext();
239+
const { addNotification } = useNotificationApi();
240+
const [inProgress, setInProgress] = useState(false);
241+
242+
const title = t('Leave Channel');
243+
244+
return (
245+
<ContextMenuButton
246+
aria-label={title}
247+
disabled={inProgress}
248+
Icon={IconLeave}
249+
onClick={async (e) => {
250+
e.stopPropagation();
251+
try {
252+
setInProgress(true);
253+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
254+
await channel.removeMembers([client.userID!]);
255+
addNotification({
256+
context: {
257+
channel,
258+
},
259+
emitter: ChannelListItemActionButtons.name,
260+
message: t('Left channel'),
261+
severity: 'success',
262+
type: 'api:channel:leave:success',
263+
});
264+
} catch (error) {
265+
addNotification({
266+
context: {
267+
channel,
268+
},
269+
emitter: ChannelListItemActionButtons.name,
270+
error:
271+
error instanceof Error ? error : new Error('An unknown error occurred'),
272+
message: t('Failed to leave channel'),
273+
severity: 'error',
274+
type: 'api:channel:leave:failed',
275+
});
276+
} finally {
277+
setInProgress(false);
278+
}
279+
}}
280+
title={title}
281+
variant='destructive'
282+
>
283+
{title}
284+
</ContextMenuButton>
285+
);
286+
},
287+
Mute() {
288+
const behaviorProps = useMuteActionButtonBehavior();
289+
290+
return (
291+
<ContextMenuButton
292+
aria-label={behaviorProps.title}
293+
Icon={IconMute}
294+
{...behaviorProps}
295+
>
296+
{behaviorProps.title}
297+
</ContextMenuButton>
298+
);
299+
},
300+
Pin() {
334301
const { t } = useTranslationContext();
335302
const { addNotification } = useNotificationApi();
336303
const { channel } = useChannelListItemContext();
@@ -400,62 +367,101 @@ export const defaultChannelActionSet: ChannelActionItem[] = [
400367
</ContextMenuButton>
401368
);
402369
},
403-
placement: 'dropdown',
404-
type: 'pin',
405370
},
406-
{
407-
Component() {
408-
const { t } = useTranslationContext();
409-
const { channel } = useChannelListItemContext();
410-
const { client } = useChatContext();
411-
const { addNotification } = useNotificationApi();
412-
const [inProgress, setInProgress] = useState(false);
371+
quick: {
372+
Archive() {
373+
const behaviorProps = useArchiveActionButtonBehavior();
413374

414-
const title = t('Leave Channel');
375+
return (
376+
<Button
377+
appearance='ghost'
378+
aria-label={behaviorProps.title}
379+
circular
380+
size='sm'
381+
variant='secondary'
382+
{...behaviorProps}
383+
>
384+
<IconArchive />
385+
</Button>
386+
);
387+
},
388+
Mute() {
389+
const behaviorProps = useMuteActionButtonBehavior();
415390

416391
return (
417-
<ContextMenuButton
418-
aria-label={title}
419-
disabled={inProgress}
420-
Icon={IconLeave}
421-
onClick={async (e) => {
422-
e.stopPropagation();
423-
try {
424-
setInProgress(true);
425-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
426-
await channel.removeMembers([client.userID!]);
427-
addNotification({
428-
context: {
429-
channel,
430-
},
431-
emitter: ChannelListItemActionButtons.name,
432-
message: t('Left channel'),
433-
severity: 'success',
434-
type: 'api:channel:leave:success',
435-
});
436-
} catch (error) {
437-
addNotification({
438-
context: {
439-
channel,
440-
},
441-
emitter: ChannelListItemActionButtons.name,
442-
error:
443-
error instanceof Error ? error : new Error('An unknown error occurred'),
444-
message: t('Failed to leave channel'),
445-
severity: 'error',
446-
type: 'api:channel:leave:failed',
447-
});
448-
} finally {
449-
setInProgress(false);
450-
}
451-
}}
452-
title={title}
453-
variant='destructive'
392+
<Button
393+
appearance='ghost'
394+
aria-label={behaviorProps.title}
395+
circular
396+
size='sm'
397+
variant='secondary'
398+
{...behaviorProps}
454399
>
455-
{title}
456-
</ContextMenuButton>
400+
<IconMute />
401+
</Button>
457402
);
458403
},
404+
},
405+
QuickDropdownToggle: forwardRef<HTMLButtonElement>((_, ref) => {
406+
const { channel } = useChannelListItemContext();
407+
408+
const dialogId = ChannelListItemActionButtons.getDialogId({
409+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
410+
channelId: channel.id!,
411+
});
412+
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });
413+
const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);
414+
415+
return (
416+
<Button
417+
appearance='ghost'
418+
aria-expanded={dialogIsOpen}
419+
aria-pressed={dialogIsOpen}
420+
circular
421+
onClick={(e) => {
422+
e.stopPropagation();
423+
424+
dialog.toggle();
425+
}}
426+
ref={ref}
427+
size='sm'
428+
variant='secondary'
429+
>
430+
<IconMore />
431+
</Button>
432+
);
433+
}),
434+
};
435+
436+
defaultComponents.QuickDropdownToggle.displayName = 'QuickDropdownToggle';
437+
438+
export const defaultChannelActionSet: ChannelActionItem[] = [
439+
{
440+
Component: defaultComponents.QuickDropdownToggle,
441+
placement: 'quick-dropdown-toggle',
442+
},
443+
{
444+
Component: defaultComponents.quick.Mute,
445+
placement: 'quick',
446+
type: 'mute',
447+
},
448+
{
449+
Component: defaultComponents.dropdown.Archive,
450+
placement: 'dropdown',
451+
type: 'archive',
452+
},
453+
{
454+
Component: defaultComponents.dropdown.Ban,
455+
placement: 'dropdown',
456+
type: 'ban',
457+
},
458+
{
459+
Component: defaultComponents.dropdown.Pin,
460+
placement: 'dropdown',
461+
type: 'pin',
462+
},
463+
{
464+
Component: defaultComponents.dropdown.Leave,
459465
placement: 'dropdown',
460466
type: 'leave',
461467
},
@@ -464,11 +470,6 @@ export const defaultChannelActionSet: ChannelActionItem[] = [
464470
export const useBaseChannelActionSetFilter = (channelActionSet: ChannelActionItem[]) => {
465471
const { channel } = useChannelListItemContext();
466472
const membership = useChannelMembershipState(channel);
467-
const isDirectMessageChannel =
468-
channel.type === 'messaging' &&
469-
// assuming one of the users is current user
470-
channel.data?.member_count === 2 &&
471-
channel.id?.startsWith('!members-');
472473
const memberCount = channel.data?.member_count ?? 0;
473474
const connectedUserIsMember = typeof membership.user !== 'undefined';
474475

@@ -480,17 +481,9 @@ export const useBaseChannelActionSetFilter = (channelActionSet: ChannelActionIte
480481

481482
switch (action.type) {
482483
case 'archive':
483-
return (
484-
connectedUserIsMember &&
485-
((action.placement === 'quick' && isDirectMessageChannel) ||
486-
(action.placement === 'dropdown' && !isDirectMessageChannel))
487-
);
484+
return connectedUserIsMember;
488485
case 'mute':
489-
return (
490-
ownCapabilities?.includes('mute-channel') &&
491-
((action.placement === 'dropdown' && isDirectMessageChannel) ||
492-
(action.placement === 'quick' && !isDirectMessageChannel))
493-
);
486+
return ownCapabilities?.includes('mute-channel');
494487
case 'ban':
495488
return (
496489
memberCount > 0 &&
@@ -507,11 +500,5 @@ export const useBaseChannelActionSetFilter = (channelActionSet: ChannelActionIte
507500
});
508501

509502
return filtered;
510-
}, [
511-
channelActionSet,
512-
isDirectMessageChannel,
513-
memberCount,
514-
ownCapabilities,
515-
connectedUserIsMember,
516-
]);
503+
}, [channelActionSet, memberCount, ownCapabilities, connectedUserIsMember]);
517504
};

0 commit comments

Comments
 (0)