Shared:Components:Selector: update types for union

This commit is contained in:
Timofey Boyko 2024-02-08 15:11:07 +03:00
parent 943f0944de
commit 253d82b929
9 changed files with 572 additions and 376 deletions

View File

@ -5,16 +5,26 @@ import { Body } from "./sub-components/Body";
import { Footer } from "./sub-components/Footer";
import { StyledSelector } from "./Selector.styled";
import { AccessRight, SelectorProps, TSelectorItem } from "./Selector.types";
import {
TAccessRight,
SelectorProps,
TSelectorBodySearch,
TSelectorBreadCrumbs,
TSelectorCancelButton,
TSelectorItem,
TSelectorSelectAll,
TSelectorAccessRights,
TSelectorFooterInput,
TSelectorFooterCheckbox,
} from "./Selector.types";
const Selector = ({
id,
className,
style,
headerLabel,
withoutBackButton,
onBackClick,
withHeader,
headerProps,
isBreadCrumbsLoading,
breadCrumbsLoader,
@ -35,31 +45,44 @@ const Selector = ({
selectAllIcon,
onSelectAll,
items,
renderCustomItem,
isMultiSelect,
selectedItems,
acceptButtonLabel,
onSelect,
onAccept,
rowLoader,
emptyScreenImage,
emptyScreenHeader,
emptyScreenDescription,
searchEmptyScreenImage,
searchEmptyScreenHeader,
searchEmptyScreenDescription,
submitButtonLabel,
submitButtonId,
disableSubmitButton,
onSubmit,
withCancelButton,
cancelButtonLabel,
onCancel,
withAccessRights,
accessRights,
selectedAccessRight,
onAccessRightsChange,
withCancelButton,
cancelButtonLabel,
onCancel,
withFooterInput,
footerInputHeader,
currentFooterInputValue,
emptyScreenImage,
emptyScreenHeader,
emptyScreenDescription,
withFooterCheckbox,
footerCheckboxLabel,
isChecked,
setIsChecked,
searchEmptyScreenImage,
searchEmptyScreenHeader,
searchEmptyScreenDescription,
items,
renderCustomItem,
isMultiSelect,
selectedItems,
onSelect,
rowLoader,
hasNextPage,
isNextPageLoading,
@ -67,22 +90,11 @@ const Selector = ({
totalItems,
isLoading,
withHeader,
withFooterInput,
withFooterCheckbox,
footerInputHeader,
footerCheckboxLabel,
currentFooterInputValue,
alwaysShowFooter,
disableAcceptButton,
descriptionText,
acceptButtonId,
cancelButtonId,
isChecked,
setIsChecked,
}: SelectorProps) => {
const [footerVisible, setFooterVisible] = React.useState<boolean>(false);
const [isSearch, setIsSearch] = React.useState<boolean>(false);
@ -99,26 +111,7 @@ const Selector = ({
React.useState<boolean>(isChecked || false);
const [selectedAccess, setSelectedAccess] =
React.useState<AccessRight | null>(null);
const onBackClickAction = React.useCallback(() => {
onBackClick?.();
}, [onBackClick]);
const onClearSearchAction = React.useCallback(() => {
onClearSearch?.(() => setIsSearch(false));
}, [onClearSearch]);
const onSearchAction = React.useCallback(
(value: string) => {
const v = value.trim();
if (v === "") return onClearSearchAction();
onSearch?.(v, () => setIsSearch(true));
},
[onSearch, onClearSearchAction],
);
React.useState<TAccessRight | null>(null);
const compareSelectedItems = React.useCallback(
(newList: TSelectorItem[]) => {
@ -144,12 +137,6 @@ const Selector = ({
const onSelectAction = (item: TSelectorItem) => {
onSelect?.({
...item,
id: item.id,
email: item.email || "",
avatar: item.avatar,
icon: item.icon,
label: item.label,
shared: item.shared,
});
if (isMultiSelect) {
@ -176,8 +163,6 @@ const Selector = ({
} else {
setNewSelectedItems((value) => {
value.push({
id: item.id,
email: item.email,
...item,
});
@ -203,9 +188,6 @@ const Selector = ({
});
const newItem = {
id: item.id,
email: item.email,
...item,
};
@ -247,8 +229,8 @@ const Selector = ({
}
}, [compareSelectedItems, items, newSelectedItems.length, onSelectAll]);
const onAcceptAction = () => {
onAccept?.(
const onSubmitAction = () => {
onSubmit(
newSelectedItems,
selectedAccess,
newFooterInputValue,
@ -256,12 +238,8 @@ const Selector = ({
);
};
const onCancelAction = React.useCallback(() => {
onCancel?.();
}, [onCancel]);
const onChangeAccessRightsAction = React.useCallback(
(access: AccessRight) => {
(access: TAccessRight) => {
setSelectedAccess({ ...access });
onAccessRightsChange?.(access);
},
@ -304,6 +282,94 @@ const Selector = ({
compareSelectedItems(cloneSelectedItems);
}
}, [items, selectedItems, isMultiSelect, compareSelectedItems]);
const breadCrumbsProps: TSelectorBreadCrumbs = withBreadCrumbs
? {
withBreadCrumbs,
breadCrumbs,
onSelectBreadCrumb,
breadCrumbsLoader,
isBreadCrumbsLoading,
}
: ({} as TSelectorBreadCrumbs);
const onSelectAllProps: TSelectorSelectAll = withSelectAll
? {
withSelectAll,
selectAllLabel,
selectAllIcon,
onSelectAll: onSelectAllAction,
}
: ({} as TSelectorSelectAll);
const searchProps: TSelectorBodySearch = withSearch
? {
withSearch,
searchPlaceholder,
searchLoader,
isSearchLoading,
searchValue,
setIsSearch,
onClearSearch,
isSearch,
onSearch,
isAllIndeterminate:
newSelectedItems.length !== renderedItems.length &&
newSelectedItems.length !== 0,
isAllChecked:
newSelectedItems.length === renderedItems.length &&
renderedItems.length !== 0,
}
: ({
isSearch,
setIsSearch,
isAllIndeterminate:
newSelectedItems.length !== renderedItems.length &&
newSelectedItems.length !== 0,
isAllChecked:
newSelectedItems.length === renderedItems.length &&
renderedItems.length !== 0,
} as TSelectorBodySearch);
const cancelButtonProps = withCancelButton
? { withCancelButton, onCancel, cancelButtonLabel, cancelButtonId }
: ({} as TSelectorCancelButton);
const accessRightsProps = withAccessRights
? {
withAccessRights,
accessRights,
selectedAccessRight: selectedAccess,
onAccessRightsChange: onChangeAccessRightsAction,
}
: ({} as TSelectorAccessRights);
const inputProps = withFooterInput
? {
withFooterInput,
footerInputHeader,
currentFooterInputValue: newFooterInputValue,
setNewFooterInputValue,
}
: ({
currentFooterInputValue: newFooterInputValue,
setNewFooterInputValue,
} as TSelectorFooterInput);
const checkboxProps: TSelectorFooterCheckbox = withFooterCheckbox
? {
withFooterCheckbox,
footerCheckboxLabel,
isChecked: isFooterCheckboxChecked,
setIsFooterCheckboxChecked,
setIsChecked,
}
: ({
isChecked: isFooterCheckboxChecked,
setIsFooterCheckboxChecked,
setIsChecked,
} as TSelectorFooterCheckbox);
return (
<StyledSelector
id={id}
@ -311,37 +377,15 @@ const Selector = ({
style={style}
data-testid="selector"
>
{withHeader && (
<Header
onBackClickAction={onBackClickAction}
headerLabel={headerLabel}
withoutBackButton={withoutBackButton}
/>
)}
{withHeader && <Header {...headerProps} />}
<Body
withHeader={withHeader}
footerVisible={footerVisible || !!alwaysShowFooter}
isSearch={isSearch}
isAllIndeterminate={
newSelectedItems.length !== renderedItems.length &&
newSelectedItems.length !== 0
}
isAllChecked={
newSelectedItems.length === renderedItems.length &&
renderedItems.length !== 0
}
placeholder={searchPlaceholder}
value={searchValue}
onSearch={onSearchAction}
onClearSearch={onClearSearchAction}
items={renderedItems}
isMultiSelect={isMultiSelect}
onSelect={onSelectAction}
withSelectAll={withSelectAll}
selectAllLabel={selectAllLabel}
selectAllIcon={selectAllIcon}
onSelectAll={onSelectAllAction}
// empty screen
emptyScreenImage={emptyScreenImage}
emptyScreenHeader={emptyScreenHeader}
emptyScreenDescription={emptyScreenDescription}
@ -354,49 +398,34 @@ const Selector = ({
renderCustomItem={renderCustomItem}
totalItems={totalItems || 0}
isLoading={isLoading}
searchLoader={searchLoader}
rowLoader={rowLoader}
withBreadCrumbs={withBreadCrumbs}
breadCrumbs={breadCrumbs}
onSelectBreadCrumb={onSelectBreadCrumb}
breadCrumbsLoader={breadCrumbsLoader}
isBreadCrumbsLoading={isBreadCrumbsLoading}
isSearchLoading={isSearchLoading}
withSearch={withSearch}
withFooterInput={withFooterInput}
withFooterCheckbox={withFooterCheckbox}
descriptionText={descriptionText}
// bread crumbs
{...breadCrumbsProps}
// select all
{...onSelectAllProps}
// search
{...searchProps}
/>
{(footerVisible || alwaysShowFooter) && (
<Footer
isMultiSelect={isMultiSelect}
acceptButtonLabel={acceptButtonLabel || ""}
selectedItemsCount={newSelectedItems.length}
withCancelButton={withCancelButton}
cancelButtonLabel={cancelButtonLabel}
withAccessRights={withAccessRights}
accessRights={accessRights}
selectedAccessRight={selectedAccess}
onAccept={onAcceptAction}
onCancel={onCancelAction}
onChangeAccessRights={onChangeAccessRightsAction}
withFooterInput={withFooterInput}
withFooterCheckbox={withFooterCheckbox}
footerInputHeader={footerInputHeader}
footerCheckboxLabel={footerCheckboxLabel}
currentFooterInputValue={newFooterInputValue}
setNewFooterInputValue={setNewFooterInputValue}
isFooterCheckboxChecked={isFooterCheckboxChecked}
setIsFooterCheckboxChecked={setIsFooterCheckboxChecked}
setIsChecked={setIsChecked}
disableAcceptButton={
withFooterInput
? disableAcceptButton
: disableAcceptButton && !newFooterInputValue.trim()
}
acceptButtonId={acceptButtonId}
cancelButtonId={cancelButtonId}
onSubmit={onSubmitAction}
submitButtonLabel={submitButtonLabel}
disableSubmitButton={disableSubmitButton}
submitButtonId={submitButtonId}
// cancel button
{...cancelButtonProps}
// access rights
{...accessRightsProps}
// input
{...inputProps}
// checkbox
{...checkboxProps}
/>
)}
</StyledSelector>

View File

@ -2,191 +2,367 @@ import React from "react";
import { RoomsType } from "../../enums";
import { AvatarRole } from "../avatar";
export type AccessRight = {
// header
type THeaderBackButton = {
onBackClick: () => void;
withoutBackButton: false;
};
type THeaderNonBackButton = {
onBackClick?: undefined;
withoutBackButton?: undefined;
};
export type HeaderProps = {
headerLabel: string;
} & (THeaderBackButton | THeaderNonBackButton);
type TSelectorHeader =
| {
withHeader: true;
headerProps: HeaderProps;
}
| { withHeader?: undefined; headerProps?: undefined };
// bread crumbs
export type TBreadCrumb = {
id: string | number;
label: string;
isRoom?: boolean;
minWidth?: string;
onClick?: (e: React.MouseEvent, open: boolean, item: TBreadCrumb) => void;
};
export interface BreadCrumbsProps {
breadCrumbs: TBreadCrumb[];
onSelectBreadCrumb: (item: TBreadCrumb) => void;
isLoading: boolean;
}
export type TSelectorBreadCrumbs =
| {
withBreadCrumbs: true;
breadCrumbs: TBreadCrumb[];
onSelectBreadCrumb: (item: TBreadCrumb) => void;
breadCrumbsLoader: React.ReactNode;
isBreadCrumbsLoading: boolean;
}
| {
withBreadCrumbs?: undefined;
breadCrumbs?: undefined;
onSelectBreadCrumb?: undefined;
breadCrumbsLoader?: undefined;
isBreadCrumbsLoading?: undefined;
};
// select all
export interface SelectAllProps {
label: string;
icon: string;
onSelectAll: () => void;
isChecked: boolean;
isIndeterminate: boolean;
isLoading: boolean;
rowLoader: React.ReactNode;
}
export type TSelectorSelectAll =
| {
withSelectAll: true;
selectAllLabel: string;
selectAllIcon: string;
onSelectAll: () => void;
}
| {
withSelectAll?: undefined;
selectAllLabel?: undefined;
selectAllIcon?: undefined;
onSelectAll?: undefined;
};
// search
export interface SearchProps {
placeholder?: string;
value?: string;
onSearch: (value: string, callback?: Function) => void;
onClearSearch: (callback?: Function) => void;
setIsSearch: React.Dispatch<React.SetStateAction<boolean>>;
}
type TSelectorSearch =
| {
withSearch: true;
searchLoader: React.ReactNode;
isSearchLoading: boolean;
searchPlaceholder?: string;
searchValue?: string;
onSearch: (value: string, callback?: Function) => void;
onClearSearch: (callback?: Function) => void;
}
| {
withSearch?: undefined;
searchLoader?: undefined;
isSearchLoading?: undefined;
searchPlaceholder?: string;
searchValue?: string;
onSearch?: undefined;
onClearSearch?: undefined;
};
export type TSelectorBodySearch = TSelectorSearch & {
isSearch: boolean;
setIsSearch: React.Dispatch<React.SetStateAction<boolean>>;
isAllIndeterminate: boolean;
isAllChecked: boolean;
};
// empty screen
export interface EmptyScreenProps {
image: string;
header: string;
description: string;
searchImage: string;
searchHeader: string;
searchDescription: string;
withSearch: boolean;
}
type TSelectorEmptyScreen = {
emptyScreenImage: string;
emptyScreenHeader: string;
emptyScreenDescription: string;
searchEmptyScreenImage: string;
searchEmptyScreenHeader: string;
searchEmptyScreenDescription: string;
};
// submit button
type TSelectorSubmitButton = {
submitButtonLabel: string;
disableSubmitButton: boolean;
onSubmit: (
selectedItems: TSelectorItem[],
access: TAccessRight | null,
fileName: string,
isFooterCheckboxChecked: boolean,
) => void;
submitButtonId?: string;
};
type TSelectorFooterSubmitButton = TSelectorSubmitButton & {
onSubmit: () => void;
};
// cancel button
export type TSelectorCancelButton =
| {
withCancelButton: true;
cancelButtonLabel: string;
onCancel: () => void;
cancelButtonId?: string;
}
| {
withCancelButton?: undefined;
cancelButtonLabel?: undefined;
onCancel?: undefined;
cancelButtonId?: undefined;
};
// access rights
export type TAccessRight = {
key: string;
label: string;
description?: string;
access: string | number;
};
export interface SelectorProps {
id?: string;
className?: string;
style?: React.CSSProperties;
withHeader?: boolean;
headerLabel: string;
withoutBackButton?: boolean;
onBackClick?: () => void;
withSearch?: boolean;
searchPlaceholder?: string;
searchValue?: string;
onSearch?: (value: string, callback?: Function) => void;
onClearSearch?: (callback?: Function) => void;
items?: TSelectorItem[];
onSelect?: (item: TSelectorItem) => void;
isMultiSelect?: boolean;
selectedItems?: TSelectorItem[];
acceptButtonLabel?: string;
onAccept: (
selectedItems: TSelectorItem[],
access: AccessRight | null,
fileName: string,
isFooterCheckboxChecked: boolean,
) => void;
withSelectAll?: boolean;
selectAllLabel?: string;
selectAllIcon?: string;
onSelectAll?: () => void;
withAccessRights?: boolean;
accessRights?: AccessRight[];
selectedAccessRight?: AccessRight;
onAccessRightsChange?: (access: AccessRight) => void;
withCancelButton?: boolean;
cancelButtonLabel?: string;
onCancel?: () => void;
emptyScreenImage?: string;
emptyScreenHeader?: string;
emptyScreenDescription?: string;
searchEmptyScreenImage?: string;
searchEmptyScreenHeader?: string;
searchEmptyScreenDescription?: string;
hasNextPage?: boolean;
isNextPageLoading?: boolean;
loadNextPage?:
| ((
startIndex: number,
search?: string,
...rest: unknown[]
) => Promise<void>)
| null;
totalItems?: number;
renderCustomItem?: (...args: unknown[]) => React.ReactNode | null;
isLoading?: boolean;
searchLoader?: React.ReactNode;
rowLoader?: React.ReactNode;
withBreadCrumbs?: boolean;
breadCrumbs?: TBreadCrumb[];
onSelectBreadCrumb?: (item: TBreadCrumb) => void;
breadCrumbsLoader?: React.ReactNode;
isBreadCrumbsLoading?: boolean;
isSearchLoading?: boolean;
withFooterInput?: boolean;
withFooterCheckbox?: boolean;
footerInputHeader?: string;
currentFooterInputValue?: string;
footerCheckboxLabel?: string;
alwaysShowFooter?: boolean;
disableAcceptButton?: boolean;
export type TSelectorAccessRights =
| {
withAccessRights: true;
accessRights: TAccessRight[];
selectedAccessRight: TAccessRight | null;
onAccessRightsChange: (access: TAccessRight) => void;
}
| {
withAccessRights?: undefined;
accessRights?: undefined;
selectedAccessRight?: undefined;
onAccessRightsChange?: undefined;
};
descriptionText?: string;
// footer input
acceptButtonId?: string;
cancelButtonId?: string;
isChecked?: boolean;
setIsChecked?: React.Dispatch<React.SetStateAction<boolean>>;
}
export type TSelectorInput =
| {
withFooterInput: true;
footerInputHeader: string;
currentFooterInputValue: string;
}
| {
withFooterInput?: undefined;
footerInputHeader?: undefined;
currentFooterInputValue?: undefined;
};
export interface HeaderProps {
onBackClickAction?: () => void;
withoutBackButton?: boolean;
headerLabel: string;
}
export interface BodyProps {
footerVisible: boolean;
withHeader?: boolean;
isSearch: boolean;
isAllIndeterminate?: boolean;
isAllChecked?: boolean;
placeholder?: string;
value?: string;
withSearch?: boolean;
onSearch: (value: string) => void;
onClearSearch: () => void;
items: TSelectorItem[];
renderCustomItem?: (...args: unknown[]) => React.ReactNode | null;
onSelect?: (item: TSelectorItem) => void;
isMultiSelect?: boolean;
withSelectAll?: boolean;
selectAllLabel?: string;
selectAllIcon?: string;
onSelectAll?: () => void;
emptyScreenImage?: string;
emptyScreenHeader?: string;
emptyScreenDescription?: string;
searchEmptyScreenImage?: string;
searchEmptyScreenHeader?: string;
searchEmptyScreenDescription?: string;
loadMoreItems: (startIndex: number) => void;
hasNextPage?: boolean;
isNextPageLoading?: boolean;
totalItems: number;
isLoading?: boolean;
searchLoader: React.ReactNode;
rowLoader: React.ReactNode;
withBreadCrumbs?: boolean;
breadCrumbs?: TBreadCrumb[];
onSelectBreadCrumb?: (item: TBreadCrumb) => void;
breadCrumbsLoader?: React.ReactNode;
isBreadCrumbsLoading?: boolean;
isSearchLoading?: boolean;
withFooterInput?: boolean;
withFooterCheckbox?: boolean;
descriptionText?: string;
}
export interface FooterProps {
isMultiSelect?: boolean;
acceptButtonLabel: string;
selectedItemsCount: number;
withCancelButton?: boolean;
cancelButtonLabel?: string;
withAccessRights?: boolean;
accessRights?: AccessRight[];
selectedAccessRight?: AccessRight | null;
disableAcceptButton?: boolean;
onAccept?: () => void;
onCancel?: () => void;
onChangeAccessRights?: (access: AccessRight) => void;
withFooterInput?: boolean;
withFooterCheckbox?: boolean;
footerInputHeader?: string;
currentFooterInputValue?: string;
footerCheckboxLabel?: string;
setNewFooterInputValue?: (value: string) => void;
isFooterCheckboxChecked?: boolean;
setIsFooterCheckboxChecked?: React.Dispatch<React.SetStateAction<boolean>>;
setIsChecked?: React.Dispatch<React.SetStateAction<boolean>>;
acceptButtonId?: string;
cancelButtonId?: string;
}
export type TSelectorItem = {
key?: string;
id?: string | number;
label: string;
avatar?: string;
icon?: string;
role?: AvatarRole;
isSelected?: boolean;
email?: string;
isDisabled?: boolean;
color?: string;
fileExst?: string;
roomType?: RoomsType;
shared: boolean;
export type TSelectorFooterInput = TSelectorInput & {
setNewFooterInputValue: React.Dispatch<React.SetStateAction<string>>;
};
export interface SearchProps {
placeholder?: string;
value?: string;
onSearch: (value: string) => void;
onClearSearch: () => void;
}
// footer checkbox
export type TSelectorCheckbox =
| {
withFooterCheckbox: true;
footerCheckboxLabel: string;
isChecked: boolean;
setIsChecked: React.Dispatch<React.SetStateAction<boolean>>;
}
| {
withFooterCheckbox?: undefined;
footerCheckboxLabel?: undefined;
isChecked: boolean;
setIsChecked?: undefined;
};
export type TSelectorFooterCheckbox = TSelectorCheckbox & {
setIsFooterCheckboxChecked: React.Dispatch<React.SetStateAction<boolean>>;
};
export type SelectorProps = TSelectorHeader &
TSelectorSelectAll &
TSelectorEmptyScreen &
TSelectorSearch &
TSelectorBreadCrumbs &
TSelectorSubmitButton &
TSelectorCancelButton &
TSelectorAccessRights &
TSelectorInput &
TSelectorCheckbox & {
id?: string;
className?: string;
style?: React.CSSProperties;
items: TSelectorItem[];
onSelect?: (item: TSelectorItem) => void;
isMultiSelect: boolean;
selectedItems?: TSelectorItem[];
withAccessRights?: boolean;
accessRights?: TAccessRight[];
selectedAccessRight?: TAccessRight;
onAccessRightsChange?: (access: TAccessRight) => void;
loadNextPage:
| ((
startIndex: number,
search?: string,
...rest: unknown[]
) => Promise<void>)
| null;
hasNextPage: boolean;
isNextPageLoading: boolean;
totalItems: number;
isLoading: boolean;
rowLoader: React.ReactNode;
renderCustomItem?: (...args: unknown[]) => React.ReactNode | null;
alwaysShowFooter?: boolean;
descriptionText?: string;
};
export type BodyProps = TSelectorBreadCrumbs &
TSelectorBodySearch &
TSelectorSelectAll &
TSelectorEmptyScreen &
TSelectorBreadCrumbs & {
footerVisible: boolean;
withHeader?: boolean;
value?: string;
isMultiSelect: boolean;
items: TSelectorItem[];
renderCustomItem?: (...args: unknown[]) => React.ReactNode | null;
onSelect: (item: TSelectorItem) => void;
loadMoreItems: (startIndex: number) => void;
hasNextPage: boolean;
isNextPageLoading: boolean;
totalItems: number;
isLoading: boolean;
rowLoader: React.ReactNode;
withFooterInput?: boolean;
withFooterCheckbox?: boolean;
descriptionText?: string;
};
export type FooterProps = TSelectorFooterSubmitButton &
TSelectorCancelButton &
TSelectorAccessRights &
TSelectorFooterInput &
TSelectorFooterCheckbox & {
isMultiSelect: boolean;
selectedItemsCount: number;
};
type TSelectorItemLogo =
| {
color?: undefined;
icon?: undefined;
avatar: string;
role?: AvatarRole;
}
| { color: string; icon: undefined; avatar?: string; role?: undefined }
| { color?: undefined; icon: string; avatar?: undefined; role?: undefined };
type TSelectorItemType =
| {
email: string;
fileExst?: undefined;
roomType?: undefined;
shared?: undefined;
}
| {
email?: undefined;
fileExst: string;
roomType?: undefined;
shared?: boolean;
}
| {
email?: undefined;
fileExst?: undefined;
roomType: RoomsType;
shared?: boolean;
}
| {
email?: undefined;
fileExst?: undefined;
roomType?: undefined;
shared?: boolean;
};
export type TSelectorItem = TSelectorItemLogo &
TSelectorItemType & {
key?: string;
id?: string | number;
label: string;
isSelected?: boolean;
isDisabled?: boolean;
};
export type Data = {
items: TSelectorItem[];
@ -197,40 +373,12 @@ export type Data = {
renderCustomItem?: (...args: unknown[]) => React.ReactNode | null;
};
export interface SelectAllProps {
label?: string;
icon?: string;
onSelectAll?: () => void;
isChecked?: boolean;
isIndeterminate?: boolean;
isLoading?: boolean;
rowLoader: React.ReactNode;
}
export interface ItemProps {
index: number;
style: React.CSSProperties;
data: Data;
}
export interface EmptyScreenProps {
image?: string;
header?: string;
description?: string;
searchImage?: string;
searchHeader?: string;
searchDescription?: string;
withSearch: boolean;
}
export type TBreadCrumb = {
id: string | number;
label: string;
isRoom?: boolean;
minWidth?: string;
onClick?: (e: React.MouseEvent, open: boolean, item: TBreadCrumb) => void;
};
export type TDisplayedItem = {
id: string | number;
label: string;
@ -239,9 +387,3 @@ export type TDisplayedItem = {
isRoom?: boolean;
listItems?: TBreadCrumb[];
};
export interface BreadCrumbsProps {
breadCrumbs?: TBreadCrumb[];
onSelectBreadCrumb?: (item: TBreadCrumb) => void;
isLoading?: boolean;
}

View File

@ -30,8 +30,9 @@ const Body = ({
isSearch,
isAllIndeterminate,
isAllChecked,
placeholder,
value,
searchPlaceholder,
setIsSearch,
searchValue,
onSearch,
onClearSearch,
items,
@ -165,14 +166,15 @@ const Body = ({
)
) : null}
{isSearchLoading || isBreadCrumbsLoading ? (
{(withSearch && isSearchLoading) || isBreadCrumbsLoading ? (
searchLoader
) : withSearch || isSearch || (itemsCount > 0 && withSearch) ? (
) : withSearch || (itemsCount > 0 && withSearch) ? (
<Search
placeholder={placeholder}
value={value}
placeholder={searchPlaceholder}
value={searchValue}
onSearch={onSearch}
onClearSearch={onClearSearch}
setIsSearch={setIsSearch}
/>
) : null}
@ -180,7 +182,7 @@ const Body = ({
<Scrollbar style={{ height: listHeight }}>{rowLoader}</Scrollbar>
) : itemsCount === 0 ? (
<EmptyScreen
withSearch={isSearch && !!value}
withSearch={isSearch && !!searchValue}
image={emptyScreenImage}
header={emptyScreenHeader}
description={emptyScreenDescription}

View File

@ -29,7 +29,7 @@ const BreadCrumbs = ({
const onClickItem = React.useCallback(
(e: React.MouseEvent, open: boolean, item: TBreadCrumb) => {
if (isLoading) return;
onSelectBreadCrumb?.(item);
onSelectBreadCrumb(item);
},
[isLoading, onSelectBreadCrumb],
);
@ -191,7 +191,7 @@ const BreadCrumbs = ({
onClick={() => {
if (index === displayedItems.length - 1 || isLoading) return;
onSelectBreadCrumb?.({
onSelectBreadCrumb({
id: item.id,
label: item.label,
isRoom: item.isRoom,

View File

@ -12,22 +12,22 @@ import {
StyledNewNameContainer,
StyledNewNameHeader,
} from "../Selector.styled";
import { AccessRight, FooterProps } from "../Selector.types";
import { TAccessRight, FooterProps } from "../Selector.types";
const Footer = React.memo(
({
isMultiSelect,
acceptButtonLabel,
submitButtonLabel,
selectedItemsCount,
withCancelButton,
cancelButtonLabel,
withAccessRights,
accessRights,
selectedAccessRight,
onAccept,
disableAcceptButton,
onSubmit,
disableSubmitButton,
onCancel,
onChangeAccessRights,
onAccessRightsChange,
withFooterInput,
withFooterCheckbox,
@ -35,16 +35,16 @@ const Footer = React.memo(
footerCheckboxLabel,
currentFooterInputValue,
setNewFooterInputValue,
isFooterCheckboxChecked,
isChecked,
setIsFooterCheckboxChecked,
setIsChecked,
acceptButtonId,
submitButtonId,
cancelButtonId,
}: FooterProps) => {
const label =
selectedItemsCount && isMultiSelect
? `${acceptButtonLabel} (${selectedItemsCount})`
: acceptButtonLabel;
? `${submitButtonLabel} (${selectedItemsCount})`
: submitButtonLabel;
const onChangeFileName = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
@ -83,7 +83,7 @@ const Footer = React.memo(
{withFooterCheckbox && (
<Checkbox
label={footerCheckboxLabel}
isChecked={isFooterCheckboxChecked}
isChecked={isChecked}
onChange={onChangeCheckbox}
/>
)}
@ -93,7 +93,7 @@ const Footer = React.memo(
{withFooterCheckbox && !withFooterInput && (
<Checkbox
label={footerCheckboxLabel}
isChecked={isFooterCheckboxChecked}
isChecked={isChecked}
onChange={onChangeCheckbox}
className="selector_footer-checkbox"
/>
@ -101,20 +101,24 @@ const Footer = React.memo(
<StyledButtonContainer>
<Button
id={acceptButtonId}
id={submitButtonId}
className="button accept-button"
label={label}
primary
scale
size={ButtonSize.normal}
isDisabled={disableAcceptButton}
onClick={onAccept}
isDisabled={
!withFooterInput
? disableSubmitButton
: disableSubmitButton && !currentFooterInputValue.trim()
}
onClick={onSubmit}
/>
{withAccessRights && (
<StyledComboBox
onSelect={(opt?: TOption) =>
onChangeAccessRights?.({ ...opt } as AccessRight)
onAccessRightsChange?.({ ...opt } as TAccessRight)
}
options={accessRights as TOption[]}
size={ComboBoxSize.content}

View File

@ -9,7 +9,7 @@ import { StyledHeader } from "../Selector.styled";
import { HeaderProps } from "../Selector.types";
const Header = React.memo(
({ onBackClickAction, withoutBackButton, headerLabel }: HeaderProps) => {
({ onBackClick, withoutBackButton, headerLabel }: HeaderProps) => {
return (
<StyledHeader>
{!withoutBackButton && (
@ -17,7 +17,7 @@ const Header = React.memo(
className="arrow-button"
iconName={ArrowPathReactSvgUrl}
size={17}
onClick={onBackClickAction}
onClick={onBackClick}
/>
)}

View File

@ -50,9 +50,6 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
const currentRole = role || AvatarRole.user;
const defaultIcon = !!color;
const isLogo = !!icon || defaultIcon;
const onChangeAction = () => {
onSelect?.(item);
};
@ -77,22 +74,23 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
className="test-22"
isDisabled={isDisabled}
>
{!isLogo ? (
{avatar ? (
<Avatar
className="user-avatar"
source={avatar || ""}
source={avatar}
role={currentRole}
size={AvatarSize.min}
/>
) : (
) : color ? (
<RoomIcon color={color} title={label} showDefault />
) : icon ? (
<RoomIcon
color={color}
title={label}
showDefault={defaultIcon}
imgClassName="room-logo"
imgSrc={icon}
showDefault={false}
/>
)}
) : null}
{renderCustomItem ? (
renderCustomItem(label, role, email)
) : (

View File

@ -6,14 +6,35 @@ import { InputSize } from "../../text-input";
import { SearchProps } from "../Selector.types";
const Search = React.memo(
({ placeholder, value, onSearch, onClearSearch }: SearchProps) => {
({
placeholder,
value,
onSearch,
onClearSearch,
setIsSearch,
}: SearchProps) => {
const onClearSearchAction = React.useCallback(() => {
onClearSearch?.(() => setIsSearch(false));
}, [onClearSearch, setIsSearch]);
const onSearchAction = React.useCallback(
(data: string) => {
const v = data.trim();
if (v === "") return onClearSearchAction();
onSearch?.(v, () => setIsSearch(true));
},
[onClearSearchAction, onSearch, setIsSearch],
);
return (
<SearchInput
className="search-input"
placeholder={placeholder}
value={value}
onChange={onSearch}
onClearSearch={onClearSearch}
onChange={onSearchAction}
onClearSearch={onClearSearchAction}
size={InputSize.base}
/>
);

View File

@ -21,7 +21,7 @@ const SelectAll = React.memo(
if (e.target instanceof HTMLElement && e.target.closest(".checkbox"))
return;
onSelectAll?.();
onSelectAll();
};
return (
@ -32,7 +32,7 @@ const SelectAll = React.memo(
<>
<Avatar
className="select-all_avatar"
source={icon || ""}
source={icon}
role={AvatarRole.user}
size={AvatarSize.min}
/>