Compare commits
1 Commits
fdefdbd12e
...
5719743b57
| Author | SHA1 | Date | |
|---|---|---|---|
| 5719743b57 |
@@ -13,7 +13,7 @@ export const Table = styled.default.table`
|
||||
border-collapse: collapse;
|
||||
margin: 0;
|
||||
table-layout: fixed;
|
||||
background-color: ${Theme.blackWithOpacity};
|
||||
background-color: ${Theme.colors.gray900};
|
||||
`;
|
||||
|
||||
export const Thead = styled.default.thead`
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
import {useState, useEffect, useRef} from 'react';
|
||||
|
||||
import {IChannel} from 'interfaces';
|
||||
import {Label} from 'components/label';
|
||||
|
||||
import {DropdownContainer, DropdownInput, DropdownMenu, DropdownMenuItem} from './style';
|
||||
|
||||
const keys = ['ArrowDown', 'ArrowUp', 'Enter', 'Escape'];
|
||||
|
||||
interface IDropdown {
|
||||
itemKey: string;
|
||||
searchTerm?: string;
|
||||
onSelect: (key: string) => void;
|
||||
items: IChannel[];
|
||||
label: string;
|
||||
name: string;
|
||||
className?: string;
|
||||
}
|
||||
const maxNumOfItemsShown = 30;
|
||||
|
||||
export const Dropdown = (props: IDropdown): JSX.Element => {
|
||||
const {itemKey, searchTerm, onSelect, items, label, name, className} = props;
|
||||
const [showDropdownMenu, setShowDropdownMenu] = useState(false);
|
||||
const [input, setInput] = useState(searchTerm || '');
|
||||
const [filteredItems, setFilteredItems] = useState(items);
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
const allItemsRef = useRef([]);
|
||||
const parentElementRef = useRef(null);
|
||||
const scrollSelectedItemInView = index => {
|
||||
if (!parentElementRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dropdownMenu = parentElementRef.current;
|
||||
const menuItems = allItemsRef.current;
|
||||
|
||||
if (!menuItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
const menuItem = menuItems[index];
|
||||
|
||||
if (!menuItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isOutOfUpperView = menuItem.offsetTop < dropdownMenu.scrollTop;
|
||||
const isOutOfLowerView = (menuItem.offsetTop + menuItem.clientHeight) > (dropdownMenu.scrollTop + dropdownMenu.clientHeight);
|
||||
|
||||
if (isOutOfUpperView) {
|
||||
dropdownMenu.scrollTop = menuItem.offsetTop;
|
||||
} else if (isOutOfLowerView) {
|
||||
dropdownMenu.scrollTop = (menuItem.offsetTop + menuItem.clientHeight) - dropdownMenu.clientHeight;
|
||||
}
|
||||
};
|
||||
|
||||
const setSelectInput = value => {
|
||||
setInput(value);
|
||||
onSelect(value);
|
||||
};
|
||||
|
||||
const handleClickOutside = event => {
|
||||
if (!parentElementRef.current || parentElementRef.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filteredItems.length) {
|
||||
setSelectInput('');
|
||||
}
|
||||
|
||||
setShowDropdownMenu(false);
|
||||
onSelect(input);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
scrollSelectedItemInView(selectedIndex);
|
||||
}, [selectedIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', handleClickOutside, true);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleClickOutside, true);
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const filteredItems = items.filter(item => {
|
||||
if (item[itemKey].toLowerCase().indexOf(input.toLowerCase()) > -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (filteredItems.length > 0) {
|
||||
setSelectedIndex(0);
|
||||
}
|
||||
|
||||
setFilteredItems(filteredItems);
|
||||
}, [input, items, itemKey]);
|
||||
|
||||
const selectItemInFocusBy = offset => {
|
||||
const lastIndex = filteredItems.length - 1;
|
||||
const nextIndex = selectedIndex + offset;
|
||||
|
||||
if (nextIndex > lastIndex) {
|
||||
setSelectedIndex(0);
|
||||
} else if (nextIndex < 0) {
|
||||
setSelectedIndex(lastIndex);
|
||||
} else {
|
||||
setSelectedIndex(nextIndex);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnKeyDown = event => {
|
||||
if (keys.indexOf(event.key) === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [arrDown, arrUp, enter, escape] = keys;
|
||||
const moves = {
|
||||
[arrDown]: 1,
|
||||
[arrUp]: -1
|
||||
};
|
||||
const move = moves[event.key];
|
||||
|
||||
if (move !== undefined) {
|
||||
event.preventDefault();
|
||||
selectItemInFocusBy(move);
|
||||
}
|
||||
|
||||
if (event.key === enter) {
|
||||
if (filteredItems[selectedIndex]) {
|
||||
setSelectInput(filteredItems[selectedIndex][itemKey]);
|
||||
setShowDropdownMenu(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.key === escape) {
|
||||
event.preventDefault();
|
||||
setShowDropdownMenu(false);
|
||||
}
|
||||
};
|
||||
|
||||
const selectItem = (index: number) => {
|
||||
setSelectInput(filteredItems[index][itemKey]);
|
||||
setSelectedIndex(index);
|
||||
setShowDropdownMenu(false);
|
||||
};
|
||||
|
||||
const generateMenuOptions = () => {
|
||||
return filteredItems.length
|
||||
? filteredItems.slice(0, maxNumOfItemsShown).map((item, index) => {
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
ref={ref => allItemsRef.current[index] = ref}
|
||||
selected={selectedIndex === index}
|
||||
key={`dropdown-menu-item-${index}`}
|
||||
onClick={() => selectItem(index)}
|
||||
>
|
||||
{item[itemKey]}
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
})
|
||||
: (
|
||||
<DropdownMenuItem disabled={true}>
|
||||
No results found
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
const handleInput = ({target}) => {
|
||||
setInput(target.value);
|
||||
|
||||
if (!showDropdownMenu) {
|
||||
setShowDropdownMenu(true);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleDropdownMenu = () => setShowDropdownMenu(!showDropdownMenu);
|
||||
|
||||
return (
|
||||
<DropdownContainer>
|
||||
<Label
|
||||
htmlFor="autocomplete"
|
||||
text={label}
|
||||
/>
|
||||
<DropdownInput
|
||||
onKeyDown={handleOnKeyDown}
|
||||
showMenu={showDropdownMenu}
|
||||
autoComplete="off"
|
||||
name={name}
|
||||
onChange={handleInput}
|
||||
value={input}
|
||||
onClick={toggleDropdownMenu}
|
||||
className={className}
|
||||
/>
|
||||
{showDropdownMenu && (
|
||||
<DropdownMenu ref={parentElementRef} className="testId-generatedMenuOptions">
|
||||
{generateMenuOptions()}
|
||||
</DropdownMenu>
|
||||
)}
|
||||
</DropdownContainer>
|
||||
);
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
import * as styled from 'styled-components';
|
||||
import Input from 'components/forms/Input';
|
||||
import Theme from 'theme';
|
||||
|
||||
const {spacing, colors, typography, primaryBorderRadius} = Theme;
|
||||
|
||||
export const DropdownContainer = styled.default.div`
|
||||
width: 100%;
|
||||
position: relative;
|
||||
margin: ${spacing.xSmall} 0;
|
||||
`;
|
||||
|
||||
export const DropdownInput = styled.default(Input)<{showMenu?: boolean}>`
|
||||
${({showMenu}) => showMenu && styled.css`
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border-bottom-width: 0;
|
||||
`}
|
||||
`;
|
||||
|
||||
export const DropdownMenu = styled.default.div`
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
top: calc(100% - 4px);
|
||||
position: absolute;
|
||||
height: auto;
|
||||
max-height: 210px;
|
||||
border: 1px solid ${colors.gray400};
|
||||
border-top-width: 0;
|
||||
z-index: 4;
|
||||
background-color: ${colors.white};
|
||||
border-bottom-left-radius: ${primaryBorderRadius};
|
||||
border-bottom-right-radius: ${primaryBorderRadius};
|
||||
`;
|
||||
|
||||
export const DropdownMenuItem = styled.default.div<{
|
||||
active?: boolean;
|
||||
disabled?: boolean;
|
||||
selected?: boolean;
|
||||
}>`
|
||||
line-height: ${spacing.large};
|
||||
padding: ${spacing.xsmall} ${spacing.medium};
|
||||
font-size: ${typography.fontSizeS};
|
||||
word-wrap: break-word;
|
||||
${({active, selected, disabled}) => styled.css`
|
||||
background-color: ${active || selected ? colors.gray300 : 'transparent'};
|
||||
font-weight: ${selected ? 'bold' : 'normal'};
|
||||
color: ${disabled ? colors.gray500 : colors.gray900}
|
||||
|
||||
:hover{
|
||||
background-color: ${disabled ? colors.white : colors.gray300};
|
||||
cursor: ${disabled ? 'text' : 'pointer'};
|
||||
}
|
||||
`}
|
||||
`;
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
export * from './indicators';
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
import React from 'react';
|
||||
import {LoadingWheel as Loader} from 'components';
|
||||
import {SingleStreamSymbol, OfflineSymbol, MultipleStreamSymbol, Indicator} from './style';
|
||||
|
||||
export const OfflineIndicator = (): React.JSX.Element => (
|
||||
<Indicator>
|
||||
<OfflineSymbol />
|
||||
</Indicator>
|
||||
);
|
||||
export const SingleStreamIndicator = (): React.JSX.Element => (
|
||||
<Indicator className="single-stream-indicator">
|
||||
<SingleStreamSymbol className="testId-singleStreamIndicator" />
|
||||
</Indicator>
|
||||
);
|
||||
export const MultiStreamIndicator = (): React.JSX.Element => (
|
||||
<Indicator className="multi-stream-indicator">
|
||||
<MultipleStreamSymbol className="testId-multiStreamIndicator" />
|
||||
</Indicator>
|
||||
);
|
||||
export const LoadingIndicator = (): React.JSX.Element => (
|
||||
<Indicator>
|
||||
<Loader size={'medium'} className="loading-wheel" />
|
||||
</Indicator>
|
||||
);
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
import * as styled from 'styled-components';
|
||||
|
||||
export const Indicator = styled.default.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
/* Target LoadingWheel component by class name */
|
||||
.loading-wheel {
|
||||
flex: 0;
|
||||
margin: 0;
|
||||
|
||||
& span {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const IndicatorOutline = styled.default.div`
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
`;
|
||||
|
||||
export const OfflineSymbol = styled.default(IndicatorOutline)`
|
||||
border: 3px solid #707070;
|
||||
background-color: transparent;
|
||||
`;
|
||||
|
||||
export const SingleStreamSymbol = styled.default(IndicatorOutline)`
|
||||
background-color: #08BD0B;
|
||||
`;
|
||||
|
||||
export const MultipleStreamSymbol = styled.default(SingleStreamSymbol)`
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin-left: -2px;
|
||||
box-shadow: 9px 0 0 0 #08BD0B;
|
||||
`;
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
import {JSX} from 'react';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {AppStore} from 'store';
|
||||
import {SingleStreamIndicator, OfflineIndicator, MultiStreamIndicator, LoadingIndicator} from './indicators';
|
||||
|
||||
interface IPublishingStateIndicator {
|
||||
row: any;
|
||||
publishingStateKey: string;
|
||||
idKey: string;
|
||||
}
|
||||
|
||||
const PublishingStateIndicator = ({row, publishingStateKey, idKey}: IPublishingStateIndicator): JSX.Element => {
|
||||
const id = row[idKey] as string;
|
||||
const publishingState = useSelector((state: AppStore) => publishingStateKey && state[publishingStateKey as keyof AppStore]?.publishingState);
|
||||
const rowPublishingState = publishingState.find((record: any) => record[idKey] === id);
|
||||
|
||||
if (!publishingState) {
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
if (!rowPublishingState) {
|
||||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
if (!rowPublishingState.isOnline) {
|
||||
return <OfflineIndicator />;
|
||||
}
|
||||
|
||||
if (rowPublishingState.multipleStreams) {
|
||||
return <MultiStreamIndicator />;
|
||||
}
|
||||
|
||||
return <SingleStreamIndicator />;
|
||||
};
|
||||
|
||||
export default PublishingStateIndicator;
|
||||
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
import {createContext} from 'react';
|
||||
|
||||
export const ViewContext = createContext('');
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
|
||||
*/
|
||||
export * from './contexts';
|
||||
export * from './date';
|
||||
export * from './sort';
|
||||
export * from './validators';
|
||||
|
||||
Reference in New Issue
Block a user