Files
cinny/src/app/organisms/room/RoomSettings.jsx
Laurenz dc8e6e53c7 Adapt to different device widths (#401)
* Now adapting to small screen sizes, needs improvements

* Fix that site only gets into mobile mode when resized

* - Added navigation event triggered if user requests to return to navigation on compact screens
- People drawer wont be shown on compact screens
  - Still accessible using settings
  - would be duplicated UI
- mobileSize is now compactSize

* Put threshold for collapsing the base UI in a shared file

* Switch to a more simple solution using CSS media queries over JS
- Move back button to the left a bit so it doesnt get in touch with room icon

* switch from component-individual-thresholds to device-type thresholds
- <750px: Mobile
- <900px: Tablet
- >900px: Desktop

* Make Settings drawer component collapse on mobile

* Fix EmojiBoard not showing up and messing up UI when screen is smaller than 360px

* Improve code quality; allow passing classNames to IconButton
- remove unnessesary div wrappers
- use dir.side where appropriate
- rename threshold and its mixins to more descriptive names
- Rename "OPEN_NAVIGATION" to "NAVIGATION_OPENED"

* - follow BEM methology
- remove ROOM_SELECTED listener
- rename NAVIGATION_OPENED to OPEN_NAVIGATION where appropriate
- this does NOT changes that ref should be used for changing visability

* Use ref to change visability to avoid re-rendering

* Use ref to change visability to avoid re-rendering

* Fix that room component is not hidden by default.
This resulted in a broken view when application is viewed in mobile size without having selected a room since loading.

* fix: leaving a room should bring one back to navigation

Co-authored-by: Ajay Bura <32841439+ajbura@users.noreply.github.com>
2022-04-24 15:53:10 +05:30

212 lines
6.9 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import './RoomSettings.scss';
import { blurOnBubbling } from '../../atoms/button/script';
import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons';
import navigation from '../../../client/state/navigation';
import { openInviteUser, toggleRoomSettings, openNavigation } from '../../../client/action/navigation';
import * as roomActions from '../../../client/action/room';
import Text from '../../atoms/text/Text';
import RawIcon from '../../atoms/system-icons/RawIcon';
import Header, { TitleWrapper } from '../../atoms/header/Header';
import ScrollView from '../../atoms/scroll/ScrollView';
import Tabs from '../../atoms/tabs/Tabs';
import { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu';
import RoomProfile from '../../molecules/room-profile/RoomProfile';
import RoomSearch from '../../molecules/room-search/RoomSearch';
import RoomNotification from '../../molecules/room-notification/RoomNotification';
import RoomVisibility from '../../molecules/room-visibility/RoomVisibility';
import RoomAliases from '../../molecules/room-aliases/RoomAliases';
import RoomHistoryVisibility from '../../molecules/room-history-visibility/RoomHistoryVisibility';
import RoomEncryption from '../../molecules/room-encryption/RoomEncryption';
import RoomPermissions from '../../molecules/room-permissions/RoomPermissions';
import RoomMembers from '../../molecules/room-members/RoomMembers';
import UserIC from '../../../../public/res/ic/outlined/user.svg';
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg';
import SearchIC from '../../../../public/res/ic/outlined/search.svg';
import ShieldUserIC from '../../../../public/res/ic/outlined/shield-user.svg';
import LockIC from '../../../../public/res/ic/outlined/lock.svg';
import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
import LeaveArrowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
import ChevronTopIC from '../../../../public/res/ic/outlined/chevron-top.svg';
import { useForceUpdate } from '../../hooks/useForceUpdate';
const tabText = {
GENERAL: 'General',
SEARCH: 'Search',
MEMBERS: 'Members',
PERMISSIONS: 'Permissions',
SECURITY: 'Security',
};
const tabItems = [{
iconSrc: SettingsIC,
text: tabText.GENERAL,
disabled: false,
}, {
iconSrc: SearchIC,
text: tabText.SEARCH,
disabled: false,
}, {
iconSrc: UserIC,
text: tabText.MEMBERS,
disabled: false,
}, {
iconSrc: ShieldUserIC,
text: tabText.PERMISSIONS,
disabled: false,
}, {
iconSrc: LockIC,
text: tabText.SECURITY,
disabled: false,
}];
function GeneralSettings({ roomId }) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
const canInvite = room.canInvite(mx.getUserId());
return (
<>
<div className="room-settings__card">
<MenuHeader>Options</MenuHeader>
<MenuItem
disabled={!canInvite}
onClick={() => openInviteUser(roomId)}
iconSrc={AddUserIC}
>
Invite
</MenuItem>
<MenuItem
variant="danger"
onClick={() => {
if (confirm('Are you sure that you want to leave this room?')) {
roomActions.leave(roomId);
openNavigation();
}
}}
iconSrc={LeaveArrowIC}
>
Leave
</MenuItem>
</div>
<div className="room-settings__card">
<MenuHeader>Notification (Changing this will only affect you)</MenuHeader>
<RoomNotification roomId={roomId} />
</div>
<div className="room-settings__card">
<MenuHeader>Room visibility (who can join)</MenuHeader>
<RoomVisibility roomId={roomId} />
</div>
<div className="room-settings__card">
<MenuHeader>Room addresses</MenuHeader>
<RoomAliases roomId={roomId} />
</div>
</>
);
}
GeneralSettings.propTypes = {
roomId: PropTypes.string.isRequired,
};
function SecuritySettings({ roomId }) {
return (
<>
<div className="room-settings__card">
<MenuHeader>Encryption</MenuHeader>
<RoomEncryption roomId={roomId} />
</div>
<div className="room-settings__card">
<MenuHeader>Message history visibility</MenuHeader>
<RoomHistoryVisibility roomId={roomId} />
</div>
</>
);
}
SecuritySettings.propTypes = {
roomId: PropTypes.string.isRequired,
};
function RoomSettings({ roomId }) {
const [, forceUpdate] = useForceUpdate();
const [selectedTab, setSelectedTab] = useState(tabItems[0]);
const room = initMatrix.matrixClient.getRoom(roomId);
const handleTabChange = (tabItem) => {
setSelectedTab(tabItem);
};
useEffect(() => {
let mounted = true;
const settingsToggle = (isVisible, tab) => {
if (!mounted) return;
if (isVisible) {
const tabItem = tabItems.find((item) => item.text === tab);
if (tabItem) setSelectedTab(tabItem);
forceUpdate();
} else setTimeout(() => forceUpdate(), 200);
};
navigation.on(cons.events.navigation.ROOM_SETTINGS_TOGGLED, settingsToggle);
return () => {
mounted = false;
navigation.removeListener(cons.events.navigation.ROOM_SETTINGS_TOGGLED, settingsToggle);
};
}, []);
if (!navigation.isRoomSettings) return null;
return (
<div className="room-settings">
<ScrollView autoHide>
<div className="room-settings__content">
<Header>
<button
className="room-settings__header-btn"
onClick={() => toggleRoomSettings()}
type="button"
onMouseUp={(e) => blurOnBubbling(e, '.room-settings__header-btn')}
>
<TitleWrapper>
<Text variant="s1" weight="medium" primary>
{`${room.name}`}
<span style={{ color: 'var(--tc-surface-low)' }}> room settings</span>
</Text>
</TitleWrapper>
<RawIcon size="small" src={ChevronTopIC} />
</button>
</Header>
<RoomProfile roomId={roomId} />
<Tabs
items={tabItems}
defaultSelected={tabItems.findIndex((tab) => tab.text === selectedTab.text)}
onSelect={handleTabChange}
/>
<div className="room-settings__cards-wrapper">
{selectedTab.text === tabText.GENERAL && <GeneralSettings roomId={roomId} />}
{selectedTab.text === tabText.SEARCH && <RoomSearch roomId={roomId} />}
{selectedTab.text === tabText.MEMBERS && <RoomMembers roomId={roomId} />}
{selectedTab.text === tabText.PERMISSIONS && <RoomPermissions roomId={roomId} />}
{selectedTab.text === tabText.SECURITY && <SecuritySettings roomId={roomId} />}
</div>
</div>
</ScrollView>
</div>
);
}
RoomSettings.propTypes = {
roomId: PropTypes.string.isRequired,
};
export {
RoomSettings as default,
tabText,
};