import React, { useEffect, useState } 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'; var _ = require('lodash'); export type AlbumMetadata = serverApi.AlbumDetails; export type AlbumMetadataChanges = serverApi.ModifyAlbumRequest; export interface AlbumWindowState extends WindowState { albumId: 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 interface IProps { state: AlbumWindowState, dispatch: (action: any) => void, mainDispatch: (action: any) => void, } export async function getAlbumMetadata(id: number) { const query = { prop: serverApi.QueryElemProperty.albumId, propOperand: id, propOperator: serverApi.QueryFilterOp.Eq, }; var q: serverApi.QueryRequest = { query: query, offsetsLimits: { albumOffset: 0, albumLimit: 1, }, ordering: { orderBy: { type: serverApi.OrderByType.Name, }, ascending: true, }, }; const requestOpts = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(q), }; return (async () => { const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts) let json: any = await response.json(); let album = json.albums[0]; return album; })(); } export default function AlbumWindow(props: IProps) { let metadata = props.state.metadata; let pendingChanges = props.state.pendingChanges; // Effect to get the album's metadata. useEffect(() => { getAlbumMetadata(props.state.albumId) .then((m: AlbumMetadata) => { props.dispatch({ type: AlbumWindowStateActions.SetMetadata, value: m }); }) }, [metadata?.name]); // Effect to get the album's songs. useEffect(() => { if (props.state.songsOnAlbum) { return; } var q: serverApi.QueryRequest = { query: { prop: serverApi.QueryElemProperty.albumId, propOperator: serverApi.QueryFilterOp.Eq, propOperand: props.state.albumId, }, offsetsLimits: { songOffset: 0, songLimit: 100, }, ordering: { orderBy: { type: serverApi.OrderByType.Name, }, ascending: true, }, }; const requestOpts = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(q), }; (async () => { const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts) let json: any = await response.json(); props.dispatch({ type: AlbumWindowStateActions.SetSongs, value: json.songs, }); })(); }, [props.state.songsOnAlbum]); 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.albumId, 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 && } }