import React, { useEffect, useState, useReducer } from 'react'; import { Box, Typography, IconButton, CircularProgress } from '@material-ui/core'; import AlbumIcon from '@material-ui/icons/Album'; import * as serverApi from '../../../api'; import { WindowState } from '../Windows'; import StoreLinkIcon, { whichStore } from '../../common/StoreLinkIcon'; import EditableText from '../../common/EditableText'; import SubmitChangesButton from '../../common/SubmitChangesButton'; import SongTable, { SongGetters } from '../../tables/ResultsTable'; import { saveAlbumChanges } from '../../../lib/saveChanges'; import { QueryLeafBy, QueryLeafOp } from '../../../lib/query/Query'; import { queryAlbums, querySongs } from '../../../lib/backend/queries'; import { songGetters } from '../../../lib/songGetters'; import { useParams } from 'react-router'; export type AlbumMetadata = serverApi.AlbumDetails; export type AlbumMetadataChanges = serverApi.ModifyAlbumRequest; export interface AlbumWindowState extends WindowState { id: number, metadata: AlbumMetadata | null, pendingChanges: AlbumMetadataChanges | null, songsOnAlbum: any[] | null, songGetters: SongGetters, } export enum AlbumWindowStateActions { SetMetadata = "SetMetadata", SetPendingChanges = "SetPendingChanges", SetSongs = "SetSongs", Reload = "Reload", } export function AlbumWindowReducer(state: AlbumWindowState, action: any) { switch (action.type) { case AlbumWindowStateActions.SetMetadata: return { ...state, metadata: action.value } case AlbumWindowStateActions.SetPendingChanges: return { ...state, pendingChanges: action.value } case AlbumWindowStateActions.SetSongs: return { ...state, songsOnAlbum: action.value } case AlbumWindowStateActions.Reload: return { ...state, metadata: null, pendingChanges: null, songsOnAlbum: null } default: throw new Error("Unimplemented AlbumWindow state update.") } } export async function getAlbumMetadata(id: number) { return (await queryAlbums({ query: { a: QueryLeafBy.AlbumId, b: id, leafOp: QueryLeafOp.Equals, }, offset: 0, limit: 1, }))[0]; } export default function AlbumWindow(props: {}) { const { id } = useParams(); const [state, dispatch] = useReducer(AlbumWindowReducer, { id: id, metadata: null, pendingChanges: null, songGetters: songGetters, songsOnAlbum: null, }); return } export function AlbumWindowControlled(props: { state: AlbumWindowState, dispatch: (action: any) => void, }) { let { id: albumId, metadata, pendingChanges, songsOnAlbum } = props.state; let { dispatch } = props; // Effect to get the album's metadata. useEffect(() => { getAlbumMetadata(albumId) .then((m: AlbumMetadata) => { dispatch({ type: AlbumWindowStateActions.SetMetadata, value: m }); }) }, [albumId, dispatch]); // Effect to get the album's songs. useEffect(() => { if (songsOnAlbum) { return; } (async () => { const songs = await querySongs({ query: { a: QueryLeafBy.AlbumId, b: albumId, leafOp: QueryLeafOp.Equals, }, offset: 0, limit: -1, }); dispatch({ type: AlbumWindowStateActions.SetSongs, value: songs, }); })(); }, [songsOnAlbum, albumId, dispatch]); const [editingName, setEditingName] = useState(null); const name = setEditingName(v)} onChangeChangedValue={(v: string | null) => { let newVal: any = { ...pendingChanges }; if (v) { newVal.name = v } else { delete newVal.name } props.dispatch({ type: AlbumWindowStateActions.SetPendingChanges, value: newVal, }) }} /> const storeLinks = metadata?.storeLinks && metadata?.storeLinks.map((link: string) => { const store = whichStore(link); return store && }); const [applying, setApplying] = useState(false); const maybeSubmitButton = pendingChanges && Object.keys(pendingChanges).length > 0 && { setApplying(true); saveAlbumChanges(props.state.id, pendingChanges || {}) .then(() => { setApplying(false); props.dispatch({ type: AlbumWindowStateActions.Reload }) }) }} /> {applying && } return {metadata && {name} {storeLinks} } {maybeSubmitButton} Songs in this album in your library: {props.state.songsOnAlbum && } {!props.state.songsOnAlbum && } }