Refactor of modals and storing server-side
This commit is contained in:
@ -45,56 +45,6 @@ const Notification = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
case 'share-configuration-received':
|
||||
return (
|
||||
<div className="notification__wrapper">
|
||||
<div className="notification notification--info" data-duration={duration}>
|
||||
<Icon
|
||||
name="close"
|
||||
className="notification__close-button"
|
||||
onClick={() => dispatch(removeNotification(key, true))}
|
||||
/>
|
||||
<h4 className="notification__title">
|
||||
<I18n path="modal.share_configuration.import.title" />
|
||||
</h4>
|
||||
<div className="notification__content">
|
||||
<p>
|
||||
<I18n path="modal.share_configuration.import.subtitle" />
|
||||
</p>
|
||||
<ul>
|
||||
{configuration.ui && (
|
||||
<li><I18n path="modal.share_configuration.interface" /></li>
|
||||
)}
|
||||
{configuration.spotify && (
|
||||
<li><I18n path="services.spotify.title" /></li>
|
||||
)}
|
||||
{configuration.lastfm && (
|
||||
<li><I18n path="services.lastfm.title" /></li>
|
||||
)}
|
||||
{configuration.genius && (
|
||||
<li><I18n path="services.genius.title" /></li>
|
||||
)}
|
||||
{configuration.snapcast && (
|
||||
<li><I18n path="services.snapcast.title" /></li>
|
||||
)}
|
||||
</ul>
|
||||
<p>
|
||||
<I18n path="modal.share_configuration.import.do_you_want_to_import" />
|
||||
</p>
|
||||
</div>
|
||||
<div className="notification__actions">
|
||||
<Button
|
||||
className="notification__actions__item"
|
||||
onClick={() => importConfiguration(key, configuration)}
|
||||
tracking={{ category: 'ShareConfiguration', action: 'Import' }}
|
||||
>
|
||||
<I18n path="modal.share_configuration.import.import_now" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
<div className="notification__wrapper" key={key}>
|
||||
|
||||
@ -574,20 +574,45 @@ modal:
|
||||
lyrics: Lyrics
|
||||
import_configuration:
|
||||
title: Import configuration
|
||||
configurations: Configurations to import
|
||||
import_now: Import now
|
||||
shared_config:
|
||||
no_peers: No peer connections
|
||||
recipients: Recipients
|
||||
configurations: Configurations
|
||||
import_now: Import now
|
||||
imported: Import successful
|
||||
share: Share now
|
||||
shared: Share successful
|
||||
push:
|
||||
title: Share configuration
|
||||
subtitle: Push your authorizations and interface settings to another, connected user
|
||||
pushed:
|
||||
title: Configuration received
|
||||
subtitle: Another user has shared their configuration with you
|
||||
server:
|
||||
title: Import configuration
|
||||
subtitle: Import third-party authorizations and other settings
|
||||
configurations: Configurations to import
|
||||
import_now: Import now
|
||||
config:
|
||||
label: Configurations
|
||||
ui:
|
||||
label: User interface
|
||||
description: Theme, sorting, filters, etc
|
||||
spotify:
|
||||
label: Spotify authorisation
|
||||
description: 'Logged in as %{name}'
|
||||
lastfm:
|
||||
label: LastFM authorisation
|
||||
description: 'Logged in as %{name}'
|
||||
genius:
|
||||
label: Genius authorisation
|
||||
description: 'Logged in as %{name}'
|
||||
snapcast:
|
||||
label: Snapcast
|
||||
description: Server connection details
|
||||
share_configuration:
|
||||
title: Share configuration
|
||||
subtitle: Push your authorizations and interface settings to another, connected user
|
||||
no_peers: No peer connections
|
||||
recipients: Recipients
|
||||
configurations: Configurations
|
||||
authorization: '%{service} authorization'
|
||||
logged_in_as: 'Logged in as %{name}'
|
||||
snapcast_description: Server connection details
|
||||
|
||||
@ -113,6 +113,19 @@ export function setSharedConfig(shared_config) {
|
||||
};
|
||||
}
|
||||
|
||||
export function getSharedConfig() {
|
||||
return {
|
||||
type: 'PUSHER_GET_SHARED_CONFIG',
|
||||
};
|
||||
}
|
||||
|
||||
export function sharedConfig(shared_config) {
|
||||
return {
|
||||
type: 'PUSHER_SHARED_CONFIG',
|
||||
shared_config,
|
||||
};
|
||||
}
|
||||
|
||||
export function getVersion() {
|
||||
return {
|
||||
type: 'PUSHER_GET_VERSION',
|
||||
|
||||
@ -91,14 +91,17 @@ const PusherMiddleware = (function () {
|
||||
case 'spotify_token_changed':
|
||||
store.dispatch(spotifyActions.tokenChanged(params.spotify_token));
|
||||
break;
|
||||
case 'share_configuration_received':
|
||||
case 'share_config_received':
|
||||
store.dispatch(
|
||||
uiActions.openModal(
|
||||
'import-configuration',
|
||||
{ context: 'pushed', configuration: params },
|
||||
'import-config',
|
||||
{ context: 'pushed', config: params },
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'shared_config_changed':
|
||||
store.dispatch(pusherActions.sharedConfig(params.shared_config));
|
||||
break;
|
||||
case 'notification':
|
||||
store.dispatch(uiActions.createNotification(params.notification));
|
||||
break;
|
||||
@ -326,6 +329,7 @@ const PusherMiddleware = (function () {
|
||||
clearTimeout(reconnectTimer);
|
||||
store.dispatch(pusherActions.updateConnection());
|
||||
store.dispatch(pusherActions.getConfig());
|
||||
store.dispatch(pusherActions.getSharedConfig());
|
||||
store.dispatch(pusherActions.getRadio());
|
||||
store.dispatch(pusherActions.getCommands());
|
||||
store.dispatch(pusherActions.getPinned());
|
||||
@ -476,6 +480,24 @@ const PusherMiddleware = (function () {
|
||||
);
|
||||
break;
|
||||
|
||||
case 'PUSHER_GET_SHARED_CONFIG':
|
||||
request(store, 'get_shared_config')
|
||||
.then(
|
||||
(response) => {
|
||||
store.dispatch({
|
||||
type: 'PUSHER_SHARED_CONFIG',
|
||||
shared_config: response.shared_config,
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
'Could not load shared config',
|
||||
error,
|
||||
));
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'PUSHER_SET_SHARED_CONFIG': {
|
||||
const { shared_config } = action;
|
||||
request(store, 'set_shared_config', { shared_config })
|
||||
|
||||
@ -65,6 +65,9 @@ export default function reducer(pusher = {}, action) {
|
||||
case 'PUSHER_CONFIG':
|
||||
return { ...pusher, config: action.config };
|
||||
|
||||
case 'PUSHER_SHARED_CONFIG':
|
||||
return { ...pusher, shared_config: action.shared_config };
|
||||
|
||||
case 'PUSHER_PINNED_UPDATED':
|
||||
return { ...pusher, pinned: action.pinned };
|
||||
|
||||
|
||||
@ -14,18 +14,18 @@ import * as lastfmActions from '../../services/lastfm/actions';
|
||||
import * as geniusActions from '../../services/genius/actions';
|
||||
import { i18n, I18n } from '../../locale';
|
||||
import Button from '../../components/Button';
|
||||
import { titleCase } from '../../util/helpers';
|
||||
import { useParams } from 'react-router';
|
||||
|
||||
const ImportConfiguration = () => {
|
||||
const ImportConfig = () => {
|
||||
const { source = 'pushed' } = useParams();
|
||||
const dispatch = useDispatch();
|
||||
const [selected, setSelected] = useState([]);
|
||||
const {
|
||||
configuration = {},
|
||||
context = 'server',
|
||||
} = useSelector((state) => state.ui.modal?.props || {});
|
||||
const configFromState = useSelector((state) => state.ui.modal?.props?.config || {});
|
||||
const configFromServer = useSelector((state) => state.pusher.shared_config || {});
|
||||
const config = source === 'server' ? configFromServer : configFromState;
|
||||
|
||||
useEffect(() => {
|
||||
setWindowTitle(i18n('modal.import_configuration.title'));
|
||||
setWindowTitle(i18n(`modal.shared_config.${source}.title`));
|
||||
}, []);
|
||||
|
||||
const onSelectedChanged = (name) => {
|
||||
@ -38,7 +38,7 @@ const ImportConfiguration = () => {
|
||||
|
||||
const onSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
const toImport = pick(configuration, selected);
|
||||
const toImport = pick(config, selected);
|
||||
|
||||
if (toImport.ui) {
|
||||
dispatch(setUi(toImport.ui));
|
||||
@ -66,7 +66,7 @@ const ImportConfiguration = () => {
|
||||
));
|
||||
}
|
||||
dispatch(createNotification({
|
||||
content: i18n('modal.share_configuration.import.successful'),
|
||||
content: i18n('modal.shared_config.imported'),
|
||||
}));
|
||||
|
||||
dispatch(closeModal());
|
||||
@ -75,20 +75,20 @@ const ImportConfiguration = () => {
|
||||
return (
|
||||
<Modal className="modal--share-configuration">
|
||||
<h1>
|
||||
<I18n path={`modal.import_configuration.${context}.title`} />
|
||||
<I18n path={`modal.shared_config.${source}.title`} />
|
||||
</h1>
|
||||
<h2>
|
||||
<I18n path={`modal.import_configuration.${context}.subtitle`} />
|
||||
<I18n path={`modal.shared_config.${source}.subtitle`} />
|
||||
</h2>
|
||||
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="field checkbox checkbox--block">
|
||||
<div className="name">
|
||||
<I18n path="modal.import_configuration.configurations" />
|
||||
<I18n path="modal.shared_config.config.label" />
|
||||
</div>
|
||||
<div className="input">
|
||||
|
||||
{Object.keys(configuration).filter((i) => i !== 'name').map((name) => (
|
||||
{Object.keys(config).map((name) => (
|
||||
<div className="checkbox-group__item" key={`configuration_${name}`}>
|
||||
<label>
|
||||
<input
|
||||
@ -100,7 +100,13 @@ const ImportConfiguration = () => {
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
{titleCase(name)}
|
||||
<I18n path={`modal.shared_config.config.${name}.label`} />
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n
|
||||
path={`modal.shared_config.config.${name}.description`}
|
||||
name={config[name].me?.name || 'Unknown'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -118,7 +124,7 @@ const ImportConfiguration = () => {
|
||||
onClick={onSubmit}
|
||||
tracking={{ category: 'ImportConfiguration', action: 'Import' }}
|
||||
>
|
||||
<I18n path="modal.import_configuration.import_now" />
|
||||
<I18n path="modal.shared_config.import_now" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@ -126,4 +132,4 @@ const ImportConfiguration = () => {
|
||||
);
|
||||
}
|
||||
|
||||
export default ImportConfiguration;
|
||||
export default ImportConfig;
|
||||
@ -6,8 +6,8 @@ import EditRadio from './EditRadio';
|
||||
import AddToQueue from './AddToQueue';
|
||||
import InitialSetup from './InitialSetup';
|
||||
import KioskMode from './KioskMode';
|
||||
import ShareConfiguration from './ShareConfiguration';
|
||||
import ImportConfiguration from './ImportConfiguration';
|
||||
import ShareConfig from './ShareConfig';
|
||||
import ImportConfig from './ImportConfig';
|
||||
import AddToPlaylist from './AddToPlaylist';
|
||||
import ImageZoom from './ImageZoom';
|
||||
import HotkeysInfo from './HotkeysInfo';
|
||||
@ -22,8 +22,8 @@ export default () => (
|
||||
<Route path="/modal/add-to-playlist/:uris" component={AddToPlaylist} />
|
||||
<Route path="/modal/image-zoom" component={ImageZoom} />
|
||||
<Route path="/modal/hotkeys" component={HotkeysInfo} />
|
||||
<Route path="/modal/share-configuration" component={ShareConfiguration} />
|
||||
<Route path="/modal/import-configuration" component={ImportConfiguration} />
|
||||
<Route path="/modal/share-config" component={ShareConfig} />
|
||||
<Route path="/modal/import-config/:source?" component={ImportConfig} />
|
||||
<Route path="/modal/reset" component={Reset} />
|
||||
<Route path="/modal/servers" component={Servers} />
|
||||
<Route path="/modal/edit-command/:id?" component={EditCommand} />
|
||||
|
||||
230
src/js/views/Modals/ShareConfig.js
Executable file
230
src/js/views/Modals/ShareConfig.js
Executable file
@ -0,0 +1,230 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { pick, map } from 'lodash';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Modal from './Modal';
|
||||
import {
|
||||
setWindowTitle,
|
||||
closeModal,
|
||||
createNotification,
|
||||
} from '../../services/ui/actions';
|
||||
import { deliverMessage, setSharedConfig } from '../../services/pusher/actions';
|
||||
import { i18n, I18n } from '../../locale';
|
||||
import Button from '../../components/Button';
|
||||
import { indexToArray } from '../../util/arrays';
|
||||
|
||||
const RecipientsList = ({
|
||||
selected,
|
||||
onChange,
|
||||
}) => {
|
||||
const {
|
||||
connection_id: currentConnectionId,
|
||||
connections,
|
||||
} = useSelector((state) => state.pusher);
|
||||
const connectionsArray = indexToArray(connections).filter(
|
||||
({ connection_id }) => connection_id !== currentConnectionId,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="input checkbox-group">
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="connection_server"
|
||||
checked={selected.includes('SERVER')}
|
||||
onChange={() => onChange('SERVER')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n path="modal.share_configuration.server.title" />
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n path="modal.share_configuration.server.description" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{
|
||||
connectionsArray.map(({ connection_id, username, ip }) => (
|
||||
<div key={connection_id} className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={`connection_${connection_id}`}
|
||||
checked={selected.includes(connection_id)}
|
||||
onChange={() => onChange(connection_id)}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">{username}</div>
|
||||
<div className="description mid_grey-text">{ip}</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const ShareConfig = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [recipients, setRecipients] = useState([]);
|
||||
const [selectedConfigs, setSelectedConfigs] = useState([]);
|
||||
const spotify = useSelector((state) => state.spotify);
|
||||
const genius = useSelector((state) => state.genius);
|
||||
const lastfm = useSelector((state) => state.lastfm);
|
||||
const ui = useSelector((state) => state.ui);
|
||||
const snapcast = useSelector((state) => state.snapcast);
|
||||
|
||||
useEffect(() => {
|
||||
setWindowTitle(i18n('modal.share_configuration.title'));
|
||||
}, []);
|
||||
|
||||
const onRecipientChanged = (id) => {
|
||||
setRecipients((prev) => {
|
||||
const next = [...prev];
|
||||
if (next.includes(id)) {
|
||||
const index = next.indexOf(id);
|
||||
next.splice(index, 1);
|
||||
} else {
|
||||
next.push(id);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
const onSelectedConfigChanged = (id) => {
|
||||
setSelectedConfigs((prev) => {
|
||||
const next = [...prev];
|
||||
if (next.includes(id)) {
|
||||
const index = next.indexOf(id);
|
||||
next.splice(index, 1);
|
||||
} else {
|
||||
next.push(id);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
const allConfigs = {
|
||||
ui: pick(
|
||||
ui,
|
||||
[
|
||||
'language',
|
||||
'theme',
|
||||
'smooth_scrolling_enabled',
|
||||
'hotkeys_enabled',
|
||||
'allow_reporting',
|
||||
'wide_scrollbars_enabled',
|
||||
'hide_scrollbars',
|
||||
'grid_glow_enabled',
|
||||
'sort',
|
||||
'initial_setup_complete',
|
||||
'uri_schemes_search_enabled',
|
||||
],
|
||||
),
|
||||
snapcast: pick(snapcast, ['enabled', 'host', 'port', 'ssl']),
|
||||
spotify: pick(spotify, ['authorization', 'me']),
|
||||
genius: pick(genius, ['authorization', 'me']),
|
||||
lastfm: pick(lastfm, ['authorization', 'me']),
|
||||
}
|
||||
|
||||
const onSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
const config = pick(allConfigs, selectedConfigs)
|
||||
|
||||
for (const recipient of recipients) {
|
||||
if (recipient === 'SERVER') {
|
||||
dispatch(setSharedConfig(config));
|
||||
} else {
|
||||
dispatch(
|
||||
deliverMessage(
|
||||
recipient,
|
||||
'share_config_received',
|
||||
config,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
dispatch(createNotification({
|
||||
content: i18n('modal.shared_config.shared'),
|
||||
}));
|
||||
|
||||
dispatch(closeModal());
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal className="modal--share-configuration">
|
||||
|
||||
<h1>
|
||||
<I18n path="modal.share_configuration.title" />
|
||||
</h1>
|
||||
<h2>
|
||||
<I18n path="modal.share_configuration.subtitle" />
|
||||
</h2>
|
||||
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">
|
||||
<I18n path="modal.shared_config.recipients" />
|
||||
</div>
|
||||
<RecipientsList
|
||||
selected={recipients}
|
||||
onChange={onRecipientChanged}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field checkbox checkbox--block">
|
||||
<div className="name">
|
||||
<I18n path="modal.shared_config.config.label" />
|
||||
</div>
|
||||
<div className="input">
|
||||
{map(allConfigs, (data, name) => (
|
||||
<div className="checkbox-group__item" key={name}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={name}
|
||||
checked={selectedConfigs.indexOf(name) > -1}
|
||||
onChange={() => onSelectedConfigChanged(name)}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n path={`modal.shared_config.config.${name}.label`} />
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n
|
||||
path={`modal.shared_config.config.${name}.description`}
|
||||
name={data.me?.name || 'Unknown'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="actions centered-text">
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
disabled={recipients.length <= 0}
|
||||
onClick={onSubmit}
|
||||
tracking={{ category: 'ShareConfiguration', action: 'Send' }}
|
||||
>
|
||||
<I18n path="actions.send" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ShareConfig;
|
||||
@ -1,345 +0,0 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { pick } from 'lodash';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Modal from './Modal';
|
||||
import { setWindowTitle, closeModal } from '../../services/ui/actions';
|
||||
import { deliverMessage, setSharedConfig } from '../../services/pusher/actions';
|
||||
import { i18n, I18n } from '../../locale';
|
||||
import Button from '../../components/Button';
|
||||
import { indexToArray } from '../../util/arrays';
|
||||
|
||||
const RecipientsList = ({
|
||||
selected,
|
||||
onChange,
|
||||
}) => {
|
||||
const {
|
||||
connection_id: currentConnectionId,
|
||||
connections,
|
||||
} = useSelector((state) => state.pusher);
|
||||
const connectionsArray = indexToArray(connections).filter(
|
||||
({ connection_id }) => connection_id !== currentConnectionId,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="input checkbox-group">
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="connection_server"
|
||||
checked={selected.includes('SERVER')}
|
||||
onChange={() => onChange('SERVER')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n path="modal.share_configuration.server.title" />
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n path="modal.share_configuration.server.description" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
{
|
||||
connectionsArray.map(({ connection_id, username, ip }) => (
|
||||
<div key={connection_id} className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name={`connection_${connection_id}`}
|
||||
checked={selected.includes(connection_id)}
|
||||
onChange={() => onChange(connection_id)}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">{username}</div>
|
||||
<div className="description mid_grey-text">{ip}</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const ShareConfiguration = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [recipients, setRecipients] = useState([]);
|
||||
const [selectedConfigs, setSelectedConfigs] = useState([]);
|
||||
const spotify = useSelector((state) => state.spotify);
|
||||
const genius = useSelector((state) => state.genius);
|
||||
const lastfm = useSelector((state) => state.lastfm);
|
||||
const ui = useSelector((state) => state.ui);
|
||||
const snapcast = useSelector((state) => state.snapcast);
|
||||
|
||||
useEffect(() => {
|
||||
setWindowTitle(i18n('modal.share_configuration.title'));
|
||||
}, []);
|
||||
|
||||
const onRecipientChanged = (id) => {
|
||||
setRecipients((prev) => {
|
||||
const next = [...prev];
|
||||
if (next.includes(id)) {
|
||||
const index = next.indexOf(id);
|
||||
next.splice(index, 1);
|
||||
} else {
|
||||
next.push(id);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
const onSelectedConfigChanged = (id) => {
|
||||
setSelectedConfigs((prev) => {
|
||||
const next = [...prev];
|
||||
if (next.includes(id)) {
|
||||
const index = next.indexOf(id);
|
||||
next.splice(index, 1);
|
||||
} else {
|
||||
next.push(id);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
const collateConfig = () => {
|
||||
const obj = {};
|
||||
selectedConfigs.forEach((name) => {
|
||||
switch (name) {
|
||||
case 'spotify':
|
||||
obj.spotify = pick(spotify, ['authorization', 'me']);
|
||||
break;
|
||||
case 'genius':
|
||||
obj.genius = pick(genius, ['authorization', 'me']);
|
||||
break;
|
||||
case 'lastfm':
|
||||
obj.lastfm = pick(lastfm, ['authorization', 'me']);
|
||||
break;
|
||||
case 'snapcast':
|
||||
obj.snapcast = pick(snapcast, ['enabled', 'host', 'port', 'ssl']);
|
||||
break;
|
||||
case 'ui':
|
||||
obj.ui = pick(
|
||||
ui,
|
||||
[
|
||||
'language',
|
||||
'theme',
|
||||
'smooth_scrolling_enabled',
|
||||
'hotkeys_enabled',
|
||||
'allow_reporting',
|
||||
'wide_scrollbars_enabled',
|
||||
'hide_scrollbars',
|
||||
'grid_glow_enabled',
|
||||
'sort',
|
||||
'initial_setup_complete',
|
||||
'uri_schemes_search_enabled',
|
||||
],
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
|
||||
const onSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
const configuration = collateConfig();
|
||||
|
||||
for (const recipient of recipients) {
|
||||
if (recipient === 'SERVER') {
|
||||
dispatch(setSharedConfig(configuration));
|
||||
} else {
|
||||
dispatch(
|
||||
deliverMessage(
|
||||
recipient,
|
||||
'share_configuration_received',
|
||||
configuration,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(closeModal());
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal className="modal--share-configuration">
|
||||
|
||||
<h1>
|
||||
<I18n path="modal.share_configuration.title" />
|
||||
</h1>
|
||||
<h2>
|
||||
<I18n path="modal.share_configuration.subtitle" />
|
||||
</h2>
|
||||
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="field checkbox white">
|
||||
<div className="name">
|
||||
<I18n path="modal.share_configuration.recipients" />
|
||||
</div>
|
||||
<RecipientsList
|
||||
selected={recipients}
|
||||
onChange={onRecipientChanged}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="field checkbox checkbox--block">
|
||||
<div className="name">
|
||||
<I18n path="modal.share_configuration.configurations" />
|
||||
</div>
|
||||
<div className="input">
|
||||
|
||||
{spotify?.authorization && (
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="spotify"
|
||||
checked={selectedConfigs.indexOf('spotify') > -1}
|
||||
onChange={() => onSelectedConfigChanged('spotify')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n
|
||||
path="modal.share_configuration.authorization"
|
||||
service={i18n('services.spotify.title')}
|
||||
/>
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n
|
||||
path="modal.share_configuration.logged_in_as"
|
||||
name={spotify.me?.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{lastfm?.authorization && (
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="lastfm_authorization"
|
||||
checked={selectedConfigs.indexOf('lastfm') > -1}
|
||||
onChange={() => onSelectedConfigChanged('lastfm')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n
|
||||
path="modal.share_configuration.authorization"
|
||||
service={i18n('services.lastfm.title')}
|
||||
/>
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n
|
||||
path="modal.share_configuration.logged_in_as"
|
||||
name={lastfm.me?.name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{genius?.authorization && (
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="genius_authorization"
|
||||
checked={selectedConfigs.indexOf('genius') > -1}
|
||||
onChange={() => onSelectedConfigChanged('genius')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n
|
||||
path="modal.share_configuration.authorization"
|
||||
service={i18n('services.genius.title')}
|
||||
/>
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n
|
||||
path="modal.share_configuration.logged_in_as"
|
||||
name={genius?.me?.name || 'Unknown'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="snapcast"
|
||||
checked={selectedConfigs.indexOf('snapcast') > -1}
|
||||
onChange={() => onSelectedConfigChanged('snapcast')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n path="services.snapcast.title" />
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n path="modal.share_configuration.snapcast_description" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="checkbox-group__item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="interface"
|
||||
checked={selectedConfigs.indexOf('ui') > -1}
|
||||
onChange={() => onSelectedConfigChanged('ui')}
|
||||
/>
|
||||
<div className="label">
|
||||
<div>
|
||||
<div className="title">
|
||||
<I18n path="modal.share_configuration.interface" />
|
||||
</div>
|
||||
<div className="description mid_grey-text">
|
||||
<I18n path="modal.share_configuration.interface_description" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="actions centered-text">
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
disabled={recipients.length <= 0}
|
||||
onClick={onSubmit}
|
||||
tracking={{ category: 'ShareConfiguration', action: 'Send' }}
|
||||
>
|
||||
<I18n path="actions.send" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ShareConfiguration;
|
||||
@ -113,20 +113,6 @@ class Settings extends React.Component {
|
||||
localScan();
|
||||
}
|
||||
|
||||
doImportSharedConfig = () => {
|
||||
const {
|
||||
uiActions: {
|
||||
openModal,
|
||||
},
|
||||
pusher: {
|
||||
config: {
|
||||
shared_config: configuration,
|
||||
},
|
||||
},
|
||||
} = this.props;
|
||||
openModal('import-configuration', { context: 'server', configuration });
|
||||
}
|
||||
|
||||
renderLocalScanButton = () => {
|
||||
const {
|
||||
ui: { processes },
|
||||
@ -525,11 +511,11 @@ class Settings extends React.Component {
|
||||
<I18n path="settings.advanced.shared_configuration.label" />
|
||||
</div>
|
||||
<div className="input">
|
||||
<Button to="/modal/share-configuration">
|
||||
<Button to="/modal/share-config">
|
||||
<I18n path="settings.advanced.shared_configuration.share" />
|
||||
</Button>
|
||||
{pusher.config?.shared_config && (
|
||||
<Button onClick={this.doImportSharedConfig}>
|
||||
{pusher.shared_config && (
|
||||
<Button to="/modal/import-config/server">
|
||||
<I18n path="settings.advanced.shared_configuration.import" />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user