Web: Shared: Adapt tabs to selector for people/groups
This commit is contained in:
parent
1fe703a0c9
commit
16cc8962ee
@ -6,6 +6,7 @@ import { Base } from "../../themes";
|
||||
|
||||
import { ComboBox } from "../combobox";
|
||||
import { Text } from "../text";
|
||||
import { Submenu } from "../submenu";
|
||||
|
||||
const StyledSelector = styled.div`
|
||||
width: 100%;
|
||||
@ -53,6 +54,7 @@ const StyledBody = styled.div<{
|
||||
withHeader?: boolean;
|
||||
footerHeight: number;
|
||||
headerHeight: number;
|
||||
withTabs?: boolean;
|
||||
}>`
|
||||
width: 100%;
|
||||
|
||||
@ -65,7 +67,7 @@ const StyledBody = styled.div<{
|
||||
? `calc(100% - 16px - ${props.headerHeight}px)`
|
||||
: `calc(100% - 16px)`};
|
||||
|
||||
padding: 16px 0 0 0;
|
||||
padding: ${({ withTabs }) => (withTabs ? "8px 0 0 0" : "16px 0 0 0")};
|
||||
|
||||
.search-input,
|
||||
.search-loader {
|
||||
@ -360,6 +362,15 @@ const StyledComboBox = styled(ComboBox)`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledTabs = styled(Submenu)`
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.sticky-indent {
|
||||
height: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledSelector.defaultProps = { theme: Base };
|
||||
StyledHeader.defaultProps = { theme: Base };
|
||||
StyledBody.defaultProps = { theme: Base };
|
||||
@ -384,4 +395,5 @@ export {
|
||||
StyledNewNameHeader,
|
||||
StyledButtonContainer,
|
||||
StyledComboBox,
|
||||
StyledTabs,
|
||||
};
|
||||
|
@ -83,7 +83,12 @@ const Selector = ({
|
||||
cancelButtonId,
|
||||
isChecked,
|
||||
setIsChecked,
|
||||
|
||||
withTabs,
|
||||
tabsData,
|
||||
activeTabId,
|
||||
}: SelectorProps) => {
|
||||
const [areItemsUpdated, setAreItemsUpdated] = React.useState(false);
|
||||
const [footerVisible, setFooterVisible] = React.useState<boolean>(false);
|
||||
const [isSearch, setIsSearch] = React.useState<boolean>(false);
|
||||
|
||||
@ -304,6 +309,37 @@ const Selector = ({
|
||||
compareSelectedItems(cloneSelectedItems);
|
||||
}
|
||||
}, [items, selectedItems, isMultiSelect, compareSelectedItems]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!areItemsUpdated) return;
|
||||
if (!newSelectedItems.length || !isMultiSelect || !items) {
|
||||
setAreItemsUpdated(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let hasConflict = false;
|
||||
|
||||
const cloneItems = items.map((x) => {
|
||||
if (x.isSelected) return { ...x };
|
||||
|
||||
const isSelected = newSelectedItems.some(
|
||||
(selectedItem) => selectedItem.id === x.id,
|
||||
);
|
||||
|
||||
if (isSelected) hasConflict = true;
|
||||
|
||||
return { ...x, isSelected };
|
||||
});
|
||||
|
||||
if (hasConflict) {
|
||||
setRenderedItems(cloneItems);
|
||||
}
|
||||
setAreItemsUpdated(false);
|
||||
}, [areItemsUpdated, isMultiSelect, items, newSelectedItems]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setAreItemsUpdated(true);
|
||||
}, [items]);
|
||||
return (
|
||||
<StyledSelector
|
||||
id={id}
|
||||
@ -366,6 +402,9 @@ const Selector = ({
|
||||
withFooterInput={withFooterInput}
|
||||
withFooterCheckbox={withFooterCheckbox}
|
||||
descriptionText={descriptionText}
|
||||
withTabs={withTabs}
|
||||
tabsData={tabsData}
|
||||
activeTabId={activeTabId}
|
||||
/>
|
||||
|
||||
{(footerVisible || alwaysShowFooter) && (
|
||||
@ -415,6 +454,7 @@ Selector.defaultProps = {
|
||||
alwaysShowFooter: false,
|
||||
disableAcceptButton: false,
|
||||
withHeader: true,
|
||||
withTabs: false,
|
||||
|
||||
selectedItems: [],
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { RoomsType } from "../../enums";
|
||||
import { AvatarRole } from "../avatar";
|
||||
import { TSubmenuItem } from "../submenu";
|
||||
|
||||
export type AccessRight = {
|
||||
key: string;
|
||||
@ -84,6 +85,10 @@ export interface SelectorProps {
|
||||
cancelButtonId?: string;
|
||||
isChecked?: boolean;
|
||||
setIsChecked?: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
||||
withTabs?: boolean;
|
||||
tabsData?: TSubmenuItem[];
|
||||
activeTabId?: number;
|
||||
}
|
||||
|
||||
export interface HeaderProps {
|
||||
@ -135,6 +140,10 @@ export interface BodyProps {
|
||||
withFooterCheckbox?: boolean;
|
||||
|
||||
descriptionText?: string;
|
||||
|
||||
withTabs?: boolean;
|
||||
tabsData?: TSubmenuItem[];
|
||||
activeTabId?: number;
|
||||
}
|
||||
|
||||
export interface FooterProps {
|
||||
@ -177,6 +186,7 @@ export type TSelectorItem = {
|
||||
isDisabled?: boolean;
|
||||
color?: string;
|
||||
fileExst?: string;
|
||||
isGroup?: boolean;
|
||||
roomType?: RoomsType;
|
||||
shared: boolean;
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ import { SelectAll } from "./SelectAll";
|
||||
import { EmptyScreen } from "./EmptyScreen";
|
||||
import { BreadCrumbs } from "./BreadCrumbs";
|
||||
|
||||
import { StyledBody } from "../Selector.styled";
|
||||
import { StyledBody, StyledTabs } from "../Selector.styled";
|
||||
import { BodyProps } from "../Selector.types";
|
||||
import { Item } from "./Item";
|
||||
|
||||
@ -65,6 +65,10 @@ const Body = ({
|
||||
withFooterCheckbox,
|
||||
descriptionText,
|
||||
withHeader,
|
||||
|
||||
withTabs,
|
||||
tabsData,
|
||||
activeTabId,
|
||||
}: BodyProps) => {
|
||||
const [bodyHeight, setBodyHeight] = React.useState(0);
|
||||
|
||||
@ -152,6 +156,7 @@ const Body = ({
|
||||
headerHeight={HEADER_HEIGHT}
|
||||
footerVisible={footerVisible}
|
||||
withHeader={withHeader}
|
||||
withTabs={withTabs}
|
||||
>
|
||||
{withBreadCrumbs ? (
|
||||
isBreadCrumbsLoading ? (
|
||||
@ -165,6 +170,14 @@ const Body = ({
|
||||
)
|
||||
) : null}
|
||||
|
||||
{withTabs && tabsData && (
|
||||
<StyledTabs
|
||||
startSelect={0}
|
||||
data={tabsData}
|
||||
forsedActiveItemId={activeTabId}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isSearchLoading || isBreadCrumbsLoading ? (
|
||||
searchLoader
|
||||
) : withSearch || isSearch || (itemsCount > 0 && withSearch) ? (
|
||||
|
@ -47,8 +47,17 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
|
||||
if (!item || (item && !item.id))
|
||||
return <div style={style}>{rowLoader}</div>;
|
||||
|
||||
const { label, avatar, icon, role, isSelected, isDisabled, color, email } =
|
||||
item;
|
||||
const {
|
||||
label,
|
||||
avatar,
|
||||
icon,
|
||||
role,
|
||||
isSelected,
|
||||
isDisabled,
|
||||
color,
|
||||
email,
|
||||
isGroup,
|
||||
} = item;
|
||||
|
||||
const currentRole = role || AvatarRole.user;
|
||||
|
||||
@ -87,6 +96,8 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
|
||||
source={avatar || ""}
|
||||
role={currentRole}
|
||||
size={AvatarSize.min}
|
||||
isGroup={isGroup}
|
||||
userName={isGroup ? label : ""}
|
||||
/>
|
||||
) : (
|
||||
<RoomIcon
|
||||
@ -98,7 +109,7 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
|
||||
/>
|
||||
)}
|
||||
{renderCustomItem ? (
|
||||
renderCustomItem(label, typeLabel, email)
|
||||
renderCustomItem(label, typeLabel, email, isGroup)
|
||||
) : (
|
||||
<Text
|
||||
className="label"
|
||||
|
Loading…
Reference in New Issue
Block a user