add notification mode switcher component

This commit is contained in:
Ajay Bura 2024-12-16 18:30:58 +05:30
parent feec0a8414
commit bda619800c

View file

@ -0,0 +1,117 @@
import {
Box,
Button,
config,
Icon,
Icons,
Menu,
MenuItem,
PopOut,
RectCords,
Spinner,
Text,
} from 'folds';
import { IPushRule } from 'matrix-js-sdk';
import React, { MouseEventHandler, useMemo, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import { NotificationMode, useNotificationActionsMode } from '../../../hooks/useNotificationMode';
import { stopPropagation } from '../../../utils/keyboard';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
export const useNotificationModes = (): NotificationMode[] =>
useMemo(() => [NotificationMode.NotifyLoud, NotificationMode.Notify, NotificationMode.OFF], []);
const useNotificationModeStr = (): Record<NotificationMode, string> =>
useMemo(
() => ({
[NotificationMode.OFF]: 'Disable',
[NotificationMode.Notify]: 'Notify Silent',
[NotificationMode.NotifyLoud]: 'Notify Loud',
}),
[]
);
type NotificationModeSwitcherProps = {
pushRule: IPushRule;
onChange: (mode: NotificationMode) => Promise<void>;
};
export function NotificationModeSwitcher({ pushRule, onChange }: NotificationModeSwitcherProps) {
const modes = useNotificationModes();
const modeToStr = useNotificationModeStr();
const selectedMode = useNotificationActionsMode(pushRule.actions);
const [changeState, change] = useAsyncCallback(onChange);
const changing = changeState.status === AsyncStatus.Loading;
const [menuCords, setMenuCords] = useState<RectCords>();
const handleMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
setMenuCords(evt.currentTarget.getBoundingClientRect());
};
const handleSelect = (mode: NotificationMode) => {
setMenuCords(undefined);
change(mode);
};
return (
<>
<Button
size="300"
variant="Secondary"
outlined
fill="Soft"
radii="300"
after={
changing ? (
<Spinner variant="Secondary" size="300" />
) : (
<Icon size="300" src={Icons.ChevronBottom} />
)
}
onClick={handleMenu}
disabled={changing}
>
<Text size="T300">{modeToStr[selectedMode]}</Text>
</Button>
<PopOut
anchor={menuCords}
offset={5}
position="Bottom"
align="End"
content={
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: () => setMenuCords(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) =>
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
isKeyBackward: (evt: KeyboardEvent) =>
evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
escapeDeactivates: stopPropagation,
}}
>
<Menu>
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
{modes.map((mode) => (
<MenuItem
key={mode}
size="300"
variant="Surface"
aria-selected={mode === selectedMode}
radii="300"
onClick={() => handleSelect(mode)}
>
<Box grow="Yes">
<Text size="T300">{modeToStr[mode]}</Text>
</Box>
</MenuItem>
))}
</Box>
</Menu>
</FocusTrap>
}
/>
</>
);
}