diff --git a/client/public/manifest.json b/client/public/manifest.json index 080d6c7..d3a688d 100644 --- a/client/public/manifest.json +++ b/client/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "MuDBase", + "name": "MuDBase: self-hosted music management", "icons": [ { "src": "favicon.ico", diff --git a/client/src/components/MainWindow.tsx b/client/src/components/MainWindow.tsx index 931c117..68c7142 100644 --- a/client/src/components/MainWindow.tsx +++ b/client/src/components/MainWindow.tsx @@ -1,8 +1,8 @@ -import React from 'react'; +import React, { useReducer } from 'react'; import { ThemeProvider, CssBaseline, createMuiTheme } from '@material-ui/core'; import { grey } from '@material-ui/core/colors'; import AppBar from './appbar/AppBar'; -import QueryWindow from './windows/QueryWindow'; +import QueryWindow, { QueryWindowReducer } from './windows/QueryWindow'; var _ = require('lodash'); const darkTheme = createMuiTheme({ @@ -15,9 +15,18 @@ const darkTheme = createMuiTheme({ }); export default function MainWindow(props: any) { + const [state, dispatch] = useReducer(QueryWindowReducer, { + query: null, + resultsForQuery: null, + editingQuery: false, + }); + return - + } \ No newline at end of file diff --git a/client/src/components/querybuilder/QueryBuilder.tsx b/client/src/components/querybuilder/QueryBuilder.tsx index 4fc13f7..7226e2d 100644 --- a/client/src/components/querybuilder/QueryBuilder.tsx +++ b/client/src/components/querybuilder/QueryBuilder.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Box } from '@material-ui/core'; import QBQueryButton from './QBEditButton'; import { QBQueryElem } from './QBQueryElem'; @@ -20,20 +20,20 @@ export interface Requests { export interface IProps { query: QueryElem | null, + editing: boolean, + onChangeEditing: (e: boolean) => void, onChangeQuery: (q: QueryElem | null) => void, requestFunctions: Requests, } export default function QueryBuilder(props: IProps) { - const [editing, setEditing] = useState(false); - const simpleQuery = simplify(props.query); - const showQuery = editing ? + const showQuery = props.editing ? addPlaceholders(simpleQuery, null) : simpleQuery; const onReplace = (q: any) => { const newQ = removePlaceholders(q); - setEditing(false); + props.onChangeEditing(false); props.onChangeQuery(newQ); } @@ -41,15 +41,15 @@ export default function QueryBuilder(props: IProps) { setEditing(!editing)} - editing={editing} + onClick={() => props.onChangeEditing(!props.editing)} + editing={props.editing} /> {showQuery && } diff --git a/client/src/components/windows/QueryWindow.tsx b/client/src/components/windows/QueryWindow.tsx index d2187c8..ff15103 100644 --- a/client/src/components/windows/QueryWindow.tsx +++ b/client/src/components/windows/QueryWindow.tsx @@ -18,14 +18,54 @@ const darkTheme = createMuiTheme({ }, }); -export default function QueryWindow(props: any) { - interface ResultsFor { - for: QueryElem, - results: any[], - }; +export interface ResultsForQuery { + for: QueryElem, + results: any[], +}; - const [query, setQuery] = useState(null); - const [resultsFor, setResultsFor] = useState(null); +export interface QueryWindowState { + editingQuery: boolean, + query: QueryElem | null, + resultsForQuery: ResultsForQuery | null, +} + +export enum QueryWindowStateActions { + SetQuery = "setQuery", + SetEditingQuery = "setEditingQuery", + SetResultsForQuery = "setResultsForQuery", +} + +export function QueryWindowReducer(state: QueryWindowState, action: any) { + switch (action.type) { + case QueryWindowStateActions.SetQuery: + return { ...state, query: action.value } + case QueryWindowStateActions.SetEditingQuery: + return { ...state, editingQuery: action.value } + case QueryWindowStateActions.SetResultsForQuery: + return { ...state, resultsForQuery: action.value } + default: + throw new Error("Unimplemented QueryWindow state update.") + } +} + +export interface IProps { + state: QueryWindowState, + dispatch: (action: any) => void +} + +export default function QueryWindow(props: IProps) { + let query = props.state.query; + let editing = props.state.editingQuery; + let resultsFor = props.state.resultsForQuery; + let setQuery = (q: QueryElem | null) => { + props.dispatch({ type: QueryWindowStateActions.SetQuery, value: q }); + } + let setEditingQuery = (e: boolean) => { + props.dispatch({ type: QueryWindowStateActions.SetEditingQuery, value: e }); + } + let setResultsForQuery = (r: ResultsForQuery | null) => { + props.dispatch({ type: QueryWindowStateActions.SetResultsForQuery, value: r }); + } const loading = query && (!resultsFor || !_.isEqual(resultsFor.for, query)); const showResults = (query && resultsFor && query == resultsFor.for) ? resultsFor.results : []; @@ -71,7 +111,7 @@ export default function QueryWindow(props: any) { const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts) let json: any = await response.json(); if (_.isEqual(query, _query)) { - setResultsFor({ + setResultsForQuery({ for: _query, results: json.songs, }) @@ -83,7 +123,7 @@ export default function QueryWindow(props: any) { if (query) { doQuery(query); } else { - setResultsFor(null); + setResultsForQuery(null); } }, [query]); @@ -95,6 +135,8 @@ export default function QueryWindow(props: any) {