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/api'; import { WindowState } from '../Windows'; import StoreLinkIcon, { whichStore } from '../../common/StoreLinkIcon'; import TrackTable from '../../tables/ResultsTable'; import { modifyAlbum, modifyTrack } from '../../../lib/saveChanges'; import { QueryLeafBy, QueryLeafOp } from '../../../lib/query/Query'; import { queryAlbums, queryTracks } from '../../../lib/backend/queries'; import { useParams } from 'react-router'; import { handleNotLoggedIn, NotLoggedInError } from '../../../lib/backend/request'; import { useAuth } from '../../../lib/useAuth'; import { Album, Name, Id, StoreLinks, AlbumRefs, Artist, Tag, Track, ResourceType } from '../../../api/api'; import EditItemDialog, { EditablePropertyType } from '../../common/EditItemDialog'; import EditIcon from '@material-ui/icons/Edit'; export type AlbumMetadata = serverApi.QueryResponseAlbumDetails; export type AlbumMetadataChanges = serverApi.PatchAlbumRequest; export interface AlbumWindowState extends WindowState { id: number, metadata: AlbumMetadata | null, pendingChanges: AlbumMetadataChanges | null, tracksOnAlbum: any[] | null, } export enum AlbumWindowStateActions { SetMetadata = "SetMetadata", SetPendingChanges = "SetPendingChanges", SetTracks = "SetTracks", 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.SetTracks: return { ...state, tracksOnAlbum: action.value } case AlbumWindowStateActions.Reload: return { ...state, metadata: null, pendingChanges: null, tracksOnAlbum: null } default: throw new Error("Unimplemented AlbumWindow state update.") } } export async function getAlbumMetadata(id: number): Promise { let result: any = await queryAlbums( { a: QueryLeafBy.AlbumId, b: id, leafOp: QueryLeafOp.Equals, }, 0, 1, serverApi.QueryResponseType.Details ); return result[0]; } export default function AlbumWindow(props: {}) { const { id } = useParams<{ id: string }>(); const [state, dispatch] = useReducer(AlbumWindowReducer, { id: parseInt(id), metadata: null, pendingChanges: null, tracksOnAlbum: null, }); return } export function AlbumWindowControlled(props: { state: AlbumWindowState, dispatch: (action: any) => void, }) { let { id: albumId, metadata, pendingChanges, tracksOnAlbum } = props.state; let { dispatch } = props; let auth = useAuth(); let [editing, setEditing] = useState(false); // Effect to get the album's metadata. useEffect(() => { if (metadata === null) { getAlbumMetadata(albumId) .then((m: AlbumMetadata) => { dispatch({ type: AlbumWindowStateActions.SetMetadata, value: m }); }) .catch((e: any) => { handleNotLoggedIn(auth, e) }) } }, [albumId, dispatch, metadata]); // Effect to get the album's tracks. useEffect(() => { if (tracksOnAlbum) { return; } (async () => { const tracks = await queryTracks( { a: QueryLeafBy.AlbumId, b: albumId, leafOp: QueryLeafOp.Equals, }, 0, -1, serverApi.QueryResponseType.Details ) .catch((e: any) => { handleNotLoggedIn(auth, e) }); dispatch({ type: AlbumWindowStateActions.SetTracks, value: tracks, }); })(); }, [tracksOnAlbum, albumId, dispatch]); const name = {metadata?.name || "(Unknown album name)"} const storeLinks = metadata?.storeLinks && metadata?.storeLinks.map((link: string) => { const store = whichStore(link); return store && }); return {metadata && {name} {storeLinks} { setEditing(true); }} > } Tracks in this album in your library: {props.state.tracksOnAlbum && } {!props.state.tracksOnAlbum && } {metadata && { setEditing(false); }} onSubmit={(v: serverApi.PatchAlbumRequest) => { // Remove any details about linked resources and leave only their IDs. let v_modified = { ...v, tracks: undefined, artists: undefined, tags: undefined, trackIds: v.trackIds || v.tracks?.map( (a: (Track & Id)) => { return a.id } ) || undefined, artistIds: v.artistIds || v.artists?.map( (a: (Artist & Id)) => { return a.id } ) || undefined, tagIds: v.tagIds || v.tags?.map( (t: (Tag & Id)) => { return t.id } ) || undefined, }; modifyAlbum(albumId, v_modified) .then(() => dispatch({ type: AlbumWindowStateActions.Reload })) }} id={albumId} metadata={metadata} editableProperties={[ { metadataKey: 'name', title: 'Name', type: EditablePropertyType.Text }, ]} defaultExternalLinksQuery={metadata.name} resourceType={ResourceType.Album} editStoreLinks={true} />} }