Refactor list hook filter storag

This commit is contained in:
Infinite
2020-02-16 11:56:53 +01:00
parent 6df25a2c5e
commit 151d69632e
3 changed files with 70 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
import _ from "lodash"; import _ from "lodash";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState, useEffect, useRef } from "react"; import React, { useCallback, useState, useEffect } from "react";
import { ApolloError } from "apollo-client"; import { ApolloError } from "apollo-client";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { import {
@@ -79,7 +79,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
options: IListHookOptions<QueryResult> & IQuery<QueryResult, QueryData> options: IListHookOptions<QueryResult> & IQuery<QueryResult, QueryData>
): IListHookData => { ): IListHookData => {
const [interfaceState, setInterfaceState] = useInterfaceLocalForage(); const [interfaceState, setInterfaceState] = useInterfaceLocalForage();
const forageInitialised = useRef(false); const [forageInitialised, setForageInitialised] = useState(false);
const history = useHistory(); const history = useHistory();
const location = useLocation(); const location = useLocation();
const [filter, setFilter] = useState<ListFilterModel>( const [filter, setFilter] = useState<ListFilterModel>(
@@ -96,39 +96,72 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
const totalCount = options.getCount(result); const totalCount = options.getCount(result);
const items = options.getData(result); const items = options.getData(result);
const updateInterfaceConfig = useCallback((filter: ListFilterModel) => {
setInterfaceState(config => {
const data = { ...config } as IInterfaceConfig;
data.queries = {
[options.filterMode]: {
filter: filter.makeQueryParameters(),
itemsPerPage: filter.itemsPerPage,
currentPage: filter.currentPage
}
};
return data;
});
}, [location.search, options.filterMode, setInterfaceState]);
useEffect(() => { useEffect(() => {
if (!forageInitialised.current && !interfaceState.loading) { if(interfaceState.loading)
forageInitialised.current = true; return;
if(!forageInitialised)
setForageInitialised(true);
// Don't use query parameters for sub-components // Don't use query parameters for sub-components
if (options.subComponent) return; if (options.subComponent) return;
// Don't read localForage if page already had query parameters
if (history.location.search) return;
const queryData = interfaceState.data?.queries?.[options.filterMode]; const storedQuery = interfaceState.data?.queries?.[options.filterMode];
if (!queryData) return; if (!storedQuery) return;
const newFilter = new ListFilterModel( const queryFilter = queryString.parse(location.search);
options.filterMode, const storedFilter = queryString.parse(storedQuery.filter);
queryString.parse(queryData.filter) const query = location.search ? {
); sortby: storedFilter.sortby,
newFilter.currentPage = queryData.currentPage; sortdir: storedFilter.sortdir,
newFilter.itemsPerPage = queryData.itemsPerPage; disp: storedFilter.disp,
perPage: storedFilter.perPage,
...queryFilter
} : storedFilter;
const newLocation = { ...history.location }; const newFilter = new ListFilterModel(
newLocation.search = queryData.filter; options.filterMode,
query
);
// Compare constructed filter with current filter.
// If different it's the result of navigation, and we update the filter.
const newLocation = { ...location };
newLocation.search = newFilter.makeQueryParameters();
if(newLocation.search !== filter.makeQueryParameters()) {
setFilter(newFilter);
updateInterfaceConfig(newFilter);
const newLocation = { ...location };
newLocation.search = newFilter.makeQueryParameters();
history.replace(newLocation); history.replace(newLocation);
} }
}, [ }, [
filter,
interfaceState.data, interfaceState.data,
interfaceState.loading, interfaceState.loading,
history, location,
options.subComponent, options.subComponent,
options.filterMode options.filterMode,
forageInitialised,
updateInterfaceConfig
]); ]);
/*
useEffect(() => { useEffect(() => {
if (options.subComponent) return; if (options.subComponent || !forageInitialised) return;
const newFilter = new ListFilterModel( const newFilter = new ListFilterModel(
options.filterMode, options.filterMode,
@@ -136,20 +169,8 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
); );
setFilter(newFilter); setFilter(newFilter);
if (forageInitialised.current) { }, [location, options.filterMode, options.subComponent, setInterfaceState, forageInitialised]);
setInterfaceState(config => { */
const data = { ...config } as IInterfaceConfig;
data.queries = {
[options.filterMode]: {
filter: location.search,
itemsPerPage: newFilter.itemsPerPage,
currentPage: newFilter.currentPage
}
};
return data;
});
}
}, [location, options.filterMode, options.subComponent, setInterfaceState]);
function getFilter() { function getFilter() {
if (!options.filterHook) { if (!options.filterHook) {
@@ -161,10 +182,14 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
return options.filterHook(newFilter); return options.filterHook(newFilter);
} }
function updateQueryParams(listfilter: ListFilterModel) { function updateQueryParams(listFilter: ListFilterModel) {
const newLocation = { ...history.location }; setFilter(listFilter);
newLocation.search = listfilter.makeQueryParameters(); if(!options.subComponent) {
history.replace(newLocation); const newLocation = { ...location };
newLocation.search = listFilter.makeQueryParameters();
history.replace(newLocation);
updateInterfaceConfig(listFilter);
}
} }
function onChangePageSize(pageSize: number) { function onChangePageSize(pageSize: number) {
@@ -328,7 +353,7 @@ const useList = <QueryResult extends IQueryResult, QueryData extends IDataItem>(
: undefined; : undefined;
let template; let template;
if (result.loading || !forageInitialised.current) { if (result.loading || !forageInitialised) {
template = <LoadingIndicator />; template = <LoadingIndicator />;
} else if (result.error) { } else if (result.error) {
template = <h1>{result.error.message}</h1>; template = <h1>{result.error.message}</h1>;

View File

@@ -48,7 +48,7 @@ import { makeCriteria } from "./criteria/utils";
import { DisplayMode, FilterMode } from "./types"; import { DisplayMode, FilterMode } from "./types";
interface IQueryParameters { interface IQueryParameters {
items?: string; perPage?: string;
sortby?: string; sortby?: string;
sortdir?: string; sortdir?: string;
disp?: string; disp?: string;
@@ -221,7 +221,7 @@ export class ListFilterModel {
if (params.p) { if (params.p) {
this.currentPage = Number.parseInt(params.p, 10); this.currentPage = Number.parseInt(params.p, 10);
} }
if (params.items) this.itemsPerPage = Number.parseInt(params.items, 10); if (params.perPage) this.itemsPerPage = Number.parseInt(params.perPage, 10);
if (params.c !== undefined) { if (params.c !== undefined) {
this.criteria = []; this.criteria = [];
@@ -278,11 +278,11 @@ export class ListFilterModel {
}); });
const result = { const result = {
items: perPage:
this.itemsPerPage !== DEFAULT_PARAMS.itemsPerPage this.itemsPerPage !== DEFAULT_PARAMS.itemsPerPage
? this.itemsPerPage ? this.itemsPerPage
: undefined, : undefined,
sortby: this.getSortBy(), sortby: this.sortBy !== "date" ? this.getSortBy() : undefined,
sortdir: sortdir:
this.sortDirection === SortDirectionEnum.Desc ? "desc" : undefined, this.sortDirection === SortDirectionEnum.Desc ? "desc" : undefined,
disp: disp:

View File

@@ -87,7 +87,7 @@ const renderHtmlSelect = (options: {
<td> <td>
<Form.Control <Form.Control
as="select" as="select"
readOnly={!options.isEditing} disabled={!options.isEditing}
plaintext={!options.isEditing} plaintext={!options.isEditing}
value={options.value?.toString()} value={options.value?.toString()}
onChange={(event: React.FormEvent<HTMLSelectElement>) => onChange={(event: React.FormEvent<HTMLSelectElement>) =>