dispatch/client/js/components/modals/AddChannel.js

156 lines
3.9 KiB
JavaScript
Raw Normal View History

2020-05-03 07:05:16 +00:00
import React, { memo, useState, useEffect, useRef } from 'react';
import Modal from 'react-modal';
import { useSelector, useDispatch } from 'react-redux';
2020-04-29 01:10:13 +00:00
import { FiUsers, FiX } from 'react-icons/fi';
2020-06-30 11:24:23 +00:00
import Text from 'components/Text';
2020-05-03 07:05:16 +00:00
import useModal from 'components/modals/useModal';
2019-01-23 06:34:39 +00:00
import Button from 'components/ui/Button';
import { join } from 'state/channels';
import { searchChannels } from 'state/channelSearch';
import { linkify } from 'utils';
2020-06-30 11:28:51 +00:00
import colorify from 'utils/colorify';
2019-01-23 06:34:39 +00:00
2020-06-15 08:58:51 +00:00
const Channel = memo(({ network, name, topic, userCount, joined }) => {
2020-05-03 07:05:16 +00:00
const dispatch = useDispatch();
2020-06-15 08:58:51 +00:00
const handleClick = () => dispatch(join([name], network));
2019-01-23 06:34:39 +00:00
return (
<div className="modal-channel-result">
<div className="modal-channel-result-header">
2020-05-03 07:05:16 +00:00
<h2 className="modal-channel-name" onClick={handleClick}>
2019-01-23 06:34:39 +00:00
{name}
</h2>
2020-04-29 01:10:13 +00:00
<FiUsers />
<span className="modal-channel-users">{userCount}</span>
2019-01-23 06:34:39 +00:00
{joined ? (
<span style={{ color: '#6bb758' }}>Joined</span>
) : (
<Button
className="modal-channel-button-join"
category="normal"
2020-05-03 07:05:16 +00:00
onClick={handleClick}
2019-01-23 06:34:39 +00:00
>
Join
</Button>
)}
</div>
2020-06-30 11:24:23 +00:00
<p className="modal-channel-topic">
2020-06-30 11:28:51 +00:00
<Text>{colorify(linkify(topic))}</Text>
2020-06-30 11:24:23 +00:00
</p>
2019-01-23 06:34:39 +00:00
</div>
);
});
2020-05-03 07:05:16 +00:00
const AddChannel = () => {
2020-06-15 08:58:51 +00:00
const [modal, network, closeModal] = useModal('channel');
2020-05-03 07:05:16 +00:00
const channels = useSelector(state => state.channels);
const search = useSelector(state => state.channelSearch);
const dispatch = useDispatch();
2019-01-23 06:34:39 +00:00
const [q, setQ] = useState('');
const inputEl = useRef();
const resultsEl = useRef();
const prevSearch = useRef('');
useEffect(() => {
2020-05-03 07:05:16 +00:00
if (modal.isOpen) {
2020-06-15 08:58:51 +00:00
dispatch(searchChannels(network, ''));
2020-05-03 07:05:16 +00:00
setTimeout(() => inputEl.current.focus(), 0);
} else {
2020-05-07 06:10:25 +00:00
prevSearch.current = '';
2020-05-03 07:05:16 +00:00
setQ('');
}
}, [modal.isOpen]);
2019-01-23 06:34:39 +00:00
2020-05-03 07:05:16 +00:00
const handleSearch = e => {
let nextQ = e.target.value.trim().toLowerCase();
setQ(nextQ);
2019-01-23 06:34:39 +00:00
2020-05-03 07:05:16 +00:00
if (nextQ !== q) {
resultsEl.current.scrollTop = 0;
2019-01-23 06:34:39 +00:00
2020-05-03 07:05:16 +00:00
while (nextQ.charAt(0) === '#') {
nextQ = nextQ.slice(1);
}
2019-01-23 06:34:39 +00:00
2020-05-03 07:05:16 +00:00
if (nextQ !== prevSearch.current) {
prevSearch.current = nextQ;
2020-06-15 08:58:51 +00:00
dispatch(searchChannels(network, nextQ));
2019-01-23 06:34:39 +00:00
}
2020-05-03 07:05:16 +00:00
}
};
2019-01-23 06:34:39 +00:00
2020-05-03 07:05:16 +00:00
const handleKey = e => {
2019-01-23 06:34:39 +00:00
if (e.key === 'Enter') {
let channel = e.target.value.trim();
if (channel !== '') {
2020-05-03 07:05:16 +00:00
closeModal(false);
2019-01-23 06:34:39 +00:00
if (channel.charAt(0) !== '#') {
channel = `#${channel}`;
}
2020-06-15 08:58:51 +00:00
dispatch(join([channel], network));
2019-01-23 06:34:39 +00:00
}
}
2020-05-03 07:05:16 +00:00
};
2019-01-23 06:34:39 +00:00
2020-05-03 07:05:16 +00:00
const handleLoadMore = () =>
2020-06-15 08:58:51 +00:00
dispatch(searchChannels(network, q, search.results.length));
2019-01-23 06:34:39 +00:00
let hasMore = !search.end;
if (hasMore) {
if (search.results.length < 10) {
hasMore = false;
} else if (
search.results.length > 10 &&
(search.results.length - 10) % 50 !== 0
) {
hasMore = false;
}
}
return (
2020-05-03 07:05:16 +00:00
<Modal {...modal}>
2019-01-23 06:34:39 +00:00
<div className="modal-channel-input-wrap">
<input
ref={inputEl}
type="text"
value={q}
placeholder="Enter channel name"
onKeyDown={handleKey}
onChange={handleSearch}
/>
2020-04-29 01:10:13 +00:00
<Button
icon={FiX}
className="modal-close modal-channel-close"
2020-05-03 07:05:16 +00:00
onClick={closeModal}
2019-01-25 02:57:58 +00:00
/>
2019-01-23 06:34:39 +00:00
</div>
<div ref={resultsEl} className="modal-channel-results">
{search.results.map(channel => (
<Channel
2020-06-15 08:58:51 +00:00
key={`${network} ${channel.name}`}
network={network}
joined={channels[network]?.[channel.name]?.joined}
2019-01-23 06:34:39 +00:00
{...channel}
/>
))}
{hasMore && (
<Button
className="modal-channel-button-more"
onClick={handleLoadMore}
>
Load more
</Button>
)}
</div>
2020-05-03 07:05:16 +00:00
</Modal>
2019-01-23 06:34:39 +00:00
);
};
2020-05-03 07:05:16 +00:00
export default AddChannel;