@100mslive/roomkit-react
Version:

302 lines (291 loc) • 9.45 kB
JSX
import React, { useCallback, useEffect, useState } from 'react';
import { useMedia } from 'react-use';
import { ChevronLeftIcon, CrossIcon, GridFourIcon, NotificationsIcon, SettingsIcon } from '@100mslive/react-icons';
import { HorizontalDivider } from '../../../Divider';
import { IconButton } from '../../../IconButton';
import { Box, Flex } from '../../../Layout';
import { Dialog } from '../../../Modal';
import { Sheet } from '../../../Sheet';
import { Tabs } from '../../../Tabs';
import { Text } from '../../../Text';
import { config as cssConfig } from '../../../Theme';
import DeviceSettings from './DeviceSettings';
import { LayoutSettings } from './LayoutSettings';
import { NotificationSettings } from './NotificationSettings';
import { settingContent } from './common';
const settingsList = [
{
tabName: 'devices',
title: 'Device Settings',
icon: SettingsIcon,
content: DeviceSettings,
},
{
tabName: 'notifications',
title: 'Notifications',
icon: NotificationsIcon,
content: NotificationSettings,
},
{
tabName: 'layout',
title: 'Layout',
icon: GridFourIcon,
content: LayoutSettings,
},
];
const SettingsModal = ({ open, onOpenChange, screenType, children = <></> }) => {
const mediaQueryLg = cssConfig.media.md;
const isMobile = useMedia(mediaQueryLg);
const [showSetting, setShowSetting] = useState(() =>
settingsList.reduce((obj, { tabName }) => ({ ...obj, [tabName]: true }), {}),
);
const hideSettingByTabName = useCallback(
key => hide => setShowSetting(prev => ({ ...prev, [key]: !hide })),
[setShowSetting],
);
useEffect(() => {
if (screenType === 'hls_live_streaming') {
hideSettingByTabName('layout')(true);
}
}, [screenType, hideSettingByTabName]);
const [selection, setSelection] = useState(() => Object.keys(showSetting).find(key => showSetting[key]) ?? '');
const resetSelection = useCallback(() => {
setSelection('');
}, []);
useEffect(() => {
if (isMobile) {
setSelection('');
} else {
const firstNotHiddenTabName = Object.keys(showSetting).find(key => showSetting[key]) ?? '';
setSelection(firstNotHiddenTabName);
}
}, [isMobile, showSetting]);
return isMobile ? (
<MobileSettingModal
open={open}
onOpenChange={onOpenChange}
selection={selection}
setSelection={setSelection}
showSetting={showSetting}
hideSettingByTabName={hideSettingByTabName}
resetSelection={resetSelection}
>
{children}
</MobileSettingModal>
) : (
<DesktopSettingModal
open={open}
onOpenChange={onOpenChange}
selection={selection}
setSelection={setSelection}
showSetting={showSetting}
hideSettingByTabName={hideSettingByTabName}
resetSelection={resetSelection}
>
{children}
</DesktopSettingModal>
);
};
const MobileSettingModal = ({
open,
onOpenChange,
selection,
setSelection,
showSetting,
hideSettingByTabName,
resetSelection,
children = <></>,
}) => {
return (
<Sheet.Root open={open} onOpenChange={onOpenChange}>
<Sheet.Trigger asChild>{children}</Sheet.Trigger>
<Sheet.Content
css={{
bg: '$surface_dim',
overflowY: 'auto',
}}
>
<Sheet.Title css={{ py: '$10', px: '$8', alignItems: 'center' }}>
<Flex direction="row" justify="between" css={{ w: '100%' }}>
{!selection ? (
<Text variant="h6" css={{ display: 'flex' }}>
Settings
</Text>
) : (
<Text variant="h6" css={{ display: 'flex' }}>
<Box as="span" css={{ r: '$round', mr: '$2' }} onClick={resetSelection}>
<ChevronLeftIcon />
</Box>
{selection?.charAt(0).toUpperCase() + selection.slice(1)}
</Text>
)}
<Sheet.Close>
<IconButton as="div" data-testid="dialog_cross_icon">
<CrossIcon />
</IconButton>
</Sheet.Close>
</Flex>
</Sheet.Title>
<HorizontalDivider />
{!selection ? (
<Flex
direction="column"
css={{
pb: '$8',
overflowY: 'auto',
}}
>
{settingsList
.filter(({ tabName }) => showSetting[tabName])
.map(({ icon: Icon, tabName, title }) => {
return (
<Box
key={tabName}
value={tabName}
onClick={() => {
setSelection(tabName);
}}
as="div"
css={{
all: 'unset',
fontFamily: '$sans',
p: '$10 $8',
display: 'flex',
alignItems: 'center',
fontSize: '$sm',
lineHeight: '$sm',
color: '$on_surface_high',
userSelect: 'none',
gap: '$8',
cursor: 'pointer',
'&:hover': {
bg: '$surface_brighter',
r: '$1',
gap: '$8',
border: 'none',
},
borderBottom: '1px solid $border_default',
}}
>
<Icon />
{title}
</Box>
);
})}
</Flex>
) : (
<Box
direction="column"
css={{ overflowY: 'scroll', px: '$8', py: '$10', maxHeight: '70vh', overflowX: 'hidden' }}
>
{settingsList
.filter(({ tabName }) => showSetting[tabName] && selection === tabName)
.map(({ content: Content, title, tabName }) => {
return <Content key={title} setHide={hideSettingByTabName(tabName)} />;
})}
</Box>
)}
</Sheet.Content>
</Sheet.Root>
);
};
const DesktopSettingModal = ({
open,
onOpenChange,
selection,
setSelection,
showSetting,
hideSettingByTabName,
resetSelection,
children = <></>,
}) => {
return (
<Dialog.Root open={open} onOpenChange={onOpenChange}>
<Dialog.Trigger asChild>{children}</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content
css={{
w: 'min(800px, 90%)',
height: 'min(656px, 90%)',
p: 0,
r: '$4',
}}
>
<Tabs.Root
value={selection}
activationMode="automatic"
onValueChange={setSelection}
css={{ size: '100%', position: 'relative' }}
>
<Tabs.List
css={{
w: '18.625rem',
flexDirection: 'column',
bg: '$background_default',
p: '$14 $10',
borderTopLeftRadius: '$4',
borderBottomLeftRadius: '$4',
}}
>
<Text variant="h5">Settings </Text>
<Flex direction="column" css={{ mx: 0, overflowY: 'auto', pt: '$10' }}>
{settingsList
.filter(({ tabName }) => showSetting[tabName])
.map(({ icon: Icon, tabName, title }) => {
return (
<Tabs.Trigger key={tabName} value={tabName} css={{ gap: '$8' }}>
<Icon />
{title}
</Tabs.Trigger>
);
})}
</Flex>
</Tabs.List>
{selection && (
<Flex
direction="column"
css={{
flex: '1 1 0',
minWidth: 0,
mr: '$4',
}}
>
{settingsList
.filter(({ tabName }) => showSetting[tabName])
.map(({ content: Content, title, tabName }) => {
return (
<Tabs.Content key={tabName} value={tabName} className={settingContent()}>
<SettingsContentHeader onBack={resetSelection} isMobile={false}>
{title}
</SettingsContentHeader>
<Content setHide={hideSettingByTabName(tabName)} />
</Tabs.Content>
);
})}
</Flex>
)}
</Tabs.Root>
<Dialog.Close css={{ position: 'absolute', right: '$10', top: '$10' }}>
<IconButton as="div" data-testid="dialog_cross_icon">
<CrossIcon />
</IconButton>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
};
const SettingsContentHeader = ({ children, isMobile, onBack }) => {
return (
<Text variant="h6" css={{ mb: '$12', display: 'flex', alignItems: 'center' }}>
{isMobile && (
<Box as="span" css={{ bg: '$surface_bright', mr: '$4', r: '$round', p: '$2' }} onClick={onBack}>
<ChevronLeftIcon />
</Box>
)}
{children}
</Text>
);
};
export default SettingsModal;