import React, { useState, useEffect } from 'react';
import { connect, useSelector, useDispatch } from 'react-redux';
import { bindActionCreators } from 'redux';
import { find, groupBy, map } from 'lodash';
import VolumeControl from './VolumeControl';
import MuteControl from './MuteControl';
import Icon from '../Icon';
import Thumbnail from '../Thumbnail';
import LinksSentence from '../LinksSentence';
import DropdownField from './DropdownField';
import * as coreActions from '../../services/core/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as pusherActions from '../../services/pusher/actions';
import * as snapcastActions from '../../services/snapcast/actions';
import { sortItems, indexToArray } from '../../util/arrays';
import { formatImages, digestMopidyImages } from '../../util/format';
import { titleCase } from '../../util/helpers';
import { I18n } from '../../locale';
const Header = ({ stream, server }) => {
const dispatch = useDispatch();
const {
id,
meta,
status,
uri: {
path,
},
} = stream || {};
let {
control_url,
images,
name,
artists,
} = meta || {};
const controlURL = meta?.control_url ? new URL(meta.control_url) : null;
const controlServer = controlURL ? {
url: meta.control_url,
ssl: controlURL.protocol === 'https:',
host: controlURL.hostname,
port: controlURL.port || (controlURL.protocol === 'https:' ? '443' : '80'),
} : null;
const current_server_id = useSelector((state) => state.mopidy.current_server);
const current_server = useSelector((state) => state.mopidy.servers[current_server_id]);
const isCurrentServer = control_url === current_server.url;
const isControlSwitchable = controlServer && !isCurrentServer;
if (images) images = formatImages(digestMopidyImages(controlServer, images));
const onClick = () => {
if (isControlSwitchable) {
dispatch(mopidyActions.setCurrentServer(controlServer));
}
};
return (
{server?.name || id}
{isCurrentServer && }
{status === 'playing' && }
{control_url &&
{control_url}
}
- {name || path}
{artists && }
);
}
const Group = ({
group: {
id: groupId,
name: groupName,
stream_id,
clients_ids = [],
} = {},
}) => {
const allClients = useSelector((state) => state.snapcast.clients || {});
const allStreams = indexToArray(useSelector((state) => state.snapcast.streams || {}));
const clients = clients_ids.length > 0 ? clients_ids.map((c) => allClients[c]) : [];
const dispatch = useDispatch();
return (
{titleCase(groupName)}
({ value: s.id, label: titleCase(s.id) }))}
noLabel
handleChange={
(value) => dispatch(snapcastActions.setGroupStream(groupId, value))
}
/>
{clients.map((client) => {
const {
id: clientId,
name: clientName,
mute,
volume,
} = client;
return (
{titleCase(clientName)}
dispatch(snapcastActions.setClientMute(clientId, value))
}
/>
dispatch(snapcastActions.setClientVolume(clientId, value))
}
/>
);
})}
);
};
const Outputs = () => {
const allGroups = indexToArray(useSelector((state) => state.snapcast.groups || {}));
const allStreams = useSelector((state) => state.snapcast.streams || {});
const allServers = indexToArray(useSelector((state) => state.mopidy.servers || {}));
const groupsByStream = groupBy(allGroups, 'stream_id');
return (
<>
{map(groupsByStream, (groups, id) => {
const stream = {
id,
...find(allStreams, (s) => s.id === id) || {},
server: find(allServers, (s) => s.snapcast_stream === id),
groups,
};
return (
{groups.map((group) => )}
);
})}
>
);
}
const Commands = () => {
const dispatch = useDispatch();
const commandsObj = useSelector((state) => state.pusher.commands || {});
if (!commandsObj) return null;
let items = indexToArray(commandsObj);
if (items.length <= 0) return null;
items = sortItems(items, 'sort_order');
return (
{
items.map((command) => (
dispatch(pusherActions.runCommand(command.id))}
>
))
}
);
};
const OutputControl = ({
force_expanded,
pusher_commands,
snapcast_enabled,
}) => {
const [expanded, setExpanded] = useState(false);
const handleClick = (e) => {
if (!force_expanded && $(e.target).closest('.output-control').length <= 0) {
setExpanded(false);
}
};
useEffect(() => {
if (force_expanded && !expanded) {
setExpanded(true);
}
}, [force_expanded]);
useEffect(() => {
if (expanded) {
window.addEventListener('click', handleClick, false);
} else {
window.removeEventListener('click', handleClick, false);
}
}, [expanded]);
// No customisable outputs
if (!snapcast_enabled && !pusher_commands) {
return (
);
}
if (expanded) {
const outputs = ;
const commands = ;
return (
{!outputs && !commands ? (
) : (
{commands}
{outputs}
)}
);
}
return (
);
}
const mapStateToProps = (state) => ({
pusher_connected: state.pusher.connected,
snapcast_enabled: (state.pusher.config ? state.pusher.config.snapcast_enabled : null),
});
const mapDispatchToProps = (dispatch) => ({
coreActions: bindActionCreators(coreActions, dispatch),
snapcastActions: bindActionCreators(snapcastActions, dispatch),
pusherActions: bindActionCreators(pusherActions, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(OutputControl);