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) {