import React, { useEffect, useState } from 'react'; import { AppBar, Box, Button, Dialog, DialogActions, Divider, FormControl, FormControlLabel, IconButton, Link, List, ListItem, ListItemIcon, ListItemText, MenuItem, Radio, RadioGroup, Select, Tab, Tabs, TextField, Typography } from "@material-ui/core"; import { SongMetadata } from "./SongWindow"; import StoreLinkIcon, { whichStore } from '../../common/StoreLinkIcon'; import CheckIcon from '@material-ui/icons/Check'; import SearchIcon from '@material-ui/icons/Search'; import CancelIcon from '@material-ui/icons/Cancel'; import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import DeleteIcon from '@material-ui/icons/Delete'; import { $enum } from "ts-enum-util"; import { useIntegrations, IntegrationsState, IntegrationState } from '../../../lib/integration/useIntegrations'; import { IntegrationFeature, IntegrationSong } from '../../../lib/integration/Integration'; import { TabPanel } from '@material-ui/lab'; import { v1 } from 'uuid'; import { ExternalStore } from '../../../api'; let _ = require('lodash') export function ProvideLinksWidget(props: { providers: IntegrationState[], metadata: SongMetadata, store: ExternalStore, onChange: (link: string | undefined) => void, }) { let defaultQuery = `${props.metadata.title}${props.metadata.artists && ` ${props.metadata.artists[0].name}`}${props.metadata.albums && ` ${props.metadata.albums[0].name}`}`; let [selectedProviderIdx, setSelectedProviderIdx] = useState( props.providers.length > 0 ? 0 : undefined ); let [query, setQuery] = useState(defaultQuery) let [results, setResults] = useState(undefined); let selectedProvider: IntegrationState | undefined = selectedProviderIdx !== undefined ? props.providers[selectedProviderIdx] : undefined; let currentLink = props.metadata.storeLinks ? props.metadata.storeLinks.find( (l: string) => whichStore(l) === props.store ) : undefined; // Ensure results are cleared when input state changes. useEffect(() => { setResults(undefined); setQuery(defaultQuery); }, [props.store, props.providers, props.metadata]) return Search using: setQuery(e.target.value)} label="Query" fullWidth /> { selectedProvider?.integration.searchSong(query, 10) .then((songs: IntegrationSong[]) => setResults(songs)) }} > {results && results.length > 0 && Suggestions:} props.onChange(e.target.value)}> {results && results.map((result: IntegrationSong, idx: number) => { let pretty = `"${result.title}" ${result.artist && ` by ${result.artist.name}`} ${result.album && ` (${result.album.name})`}`; return } label={ {pretty} } /> })} {results && results.length === 0 && No results were found. Try adjusting the query manually.} } export function ExternalLinksEditor(props: { metadata: SongMetadata, original: SongMetadata, onChange: (v: SongMetadata) => void, }) { let [selectedIdx, setSelectedIdx] = useState(0); let integrations = useIntegrations(); let getLinksSet = (metadata: SongMetadata) => { return $enum(ExternalStore).getValues().reduce((prev: any, store: string) => { var maybeLink: string | null = null; metadata.storeLinks && metadata.storeLinks.forEach((link: string) => { if (whichStore(link) === store) { maybeLink = link; } }) return { ...prev, [store]: maybeLink, } }, {}); } let linksSet: Record = getLinksSet(props.metadata); let originalLinksSet: Record = getLinksSet(props.original); let store = $enum(ExternalStore).getValues()[selectedIdx]; let providers: IntegrationState[] = Array.isArray(integrations.state) ? integrations.state.filter( (iState: IntegrationState) => ( iState.integration.getFeatures().includes(IntegrationFeature.SearchSong) && iState.integration.providesStoreLink() === store ) ) : []; return {$enum(ExternalStore).getValues().map((store: string, idx: number) => { let maybeLink = linksSet[store]; let color: string | undefined = (linksSet[store] && !originalLinksSet[store]) ? "lightgreen" : (!linksSet[store] && originalLinksSet[store]) ? "red" : (linksSet[store] && originalLinksSet[store] && linksSet[store] !== originalLinksSet[store]) ? "orange" : undefined; return setSelectedIdx(idx)} button > {linksSet[store] !== null ? : } {maybeLink && } {maybeLink && { let newLinks = props.metadata.storeLinks?.filter( (l: string) => whichStore(l) !== store ) props.onChange({ ...props.metadata, storeLinks: newLinks, }); }} > } })} {providers.length === 0 ? None of your configured integrations provides URL links for {store}. : { let removed = props.metadata.storeLinks?.filter( (link: string) => whichStore(link) !== store ) || []; let newValue = link ? [...removed, link] : removed; if (!_.isEqual(new Set(newValue), new Set(props.metadata.storeLinks || []))) { props.onChange({ ...props.metadata, storeLinks: newValue, }) } }} /> } } export default function EditSongDialog(props: { open: boolean, onClose: () => void, onSubmit: (v: SongMetadata) => void, id: number, metadata: SongMetadata, }) { enum EditSongTabs { Details = 0, ExternalLinks, } let [editingMetadata, setEditingMetadata] = useState(props.metadata); return Properties Under construction External Links setEditingMetadata(v)} /> {!_.isEqual(editingMetadata, props.metadata) && } }