mirror of
https://github.com/strapi/strapi.git
synced 2025-08-10 17:58:07 +00:00
Fix filters
Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
parent
3462dcac8b
commit
9cbc24c438
@ -1,9 +1,8 @@
|
||||
import React, { useReducer, useEffect } from 'react';
|
||||
import React, { useReducer, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { useIsMounted } from '@buffetjs/hooks';
|
||||
import { Select } from '@buffetjs/core';
|
||||
|
||||
import { getFilterType, request } from 'strapi-helper-plugin';
|
||||
import { getTrad } from '../../../utils';
|
||||
|
||||
@ -15,11 +14,21 @@ import FilterButton from './FilterButton';
|
||||
import FilterInput from './FilterInput';
|
||||
|
||||
const FiltersCard = ({ onChange, filters }) => {
|
||||
return null;
|
||||
const isMounted = useIsMounted();
|
||||
// Not using the hook from buffet.js because it appears that when the component is closed we the hooks returns false
|
||||
// Until we make a PR on @buffetjs/hooks I rather use this custom one
|
||||
const isMounted = useRef(true);
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const { name, filter, filtersForm, value } = state.toJS();
|
||||
|
||||
useEffect(() => {
|
||||
if (isMounted.current) {
|
||||
fetchTimestampNames();
|
||||
}
|
||||
|
||||
return () => (isMounted.current = false);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isMounted]);
|
||||
|
||||
const { name, filter, filtersForm, value } = state.toJS();
|
||||
const type = filtersForm[name].type;
|
||||
const filtersOptions = getFilterType(type);
|
||||
const options = ['image', 'video', 'file'].filter(
|
||||
@ -67,22 +76,19 @@ const FiltersCard = ({ onChange, filters }) => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
if (isMounted.current) {
|
||||
dispatch({
|
||||
type: 'HANDLE_CUSTOM_TIMESTAMPS',
|
||||
timestamps: result.data.contentType.schema.options.timestamps,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
strapi.notification.error('notification.error');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTimestampNames();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<InputWrapper>
|
||||
|
@ -28,13 +28,25 @@ function reducer(state, action) {
|
||||
return state.update(name, () => value);
|
||||
}
|
||||
case 'HANDLE_CUSTOM_TIMESTAMPS': {
|
||||
return state.set('name', action.timestamps[0]).updateIn(['filtersForm'], filtersFormMap =>
|
||||
filtersFormMap
|
||||
.set(action.timestamps[1], filtersFormMap.get('updated_at'))
|
||||
.set(action.timestamps[0], filtersFormMap.get('created_at'))
|
||||
.delete('created_at')
|
||||
.delete('updated_at')
|
||||
);
|
||||
const {
|
||||
timestamps: [created_at, updated_at],
|
||||
} = action;
|
||||
|
||||
return state
|
||||
.update('name', () => created_at)
|
||||
.updateIn(['filtersForm'], object => {
|
||||
return object.keySeq().reduce((acc, current) => {
|
||||
if (current === 'created_at') {
|
||||
return acc.set(created_at, object.get('created_at')).remove('created_at');
|
||||
}
|
||||
|
||||
if (current === 'updated_at') {
|
||||
return acc.set(updated_at, object.get('updated_at')).remove('updated_at');
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, object);
|
||||
});
|
||||
}
|
||||
case 'RESET_FORM':
|
||||
return initialState
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import reducer, { initialState } from '../reducer';
|
||||
|
||||
describe('Upload | components | FiltersCard | reducer', () => {
|
||||
@ -31,17 +32,68 @@ describe('Upload | components | FiltersCard | reducer', () => {
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
it('should return the updated filters form with custom timestamps', () => {
|
||||
const state = initialState;
|
||||
const state = fromJS({
|
||||
name: 'created_at',
|
||||
filter: '=',
|
||||
value: 'test',
|
||||
filtersForm: {
|
||||
created_at: {
|
||||
type: 'datetime',
|
||||
defaultFilter: '=',
|
||||
defaultValue: 'test1',
|
||||
},
|
||||
updated_at: {
|
||||
type: 'datetime',
|
||||
defaultFilter: '=',
|
||||
defaultValue: 'test2',
|
||||
},
|
||||
size: {
|
||||
type: 'integer',
|
||||
defaultFilter: '=',
|
||||
defaultValue: '0KB',
|
||||
},
|
||||
mime: {
|
||||
type: 'enum',
|
||||
defaultFilter: '_contains',
|
||||
defaultValue: 'image',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const action = {
|
||||
type: 'HANDLE_CUSTOM_TIMESTAMPS',
|
||||
timestamps: ['createdAtCustom', 'updatedAtCustom'],
|
||||
};
|
||||
|
||||
const actualFiltersFormKeys = Object.keys(reducer(state, action).toJS().filtersForm);
|
||||
const expectedFiltersFormKeys = ['createdAtCustom', 'updatedAtCustom', 'size', 'mime'];
|
||||
const expected = fromJS({
|
||||
name: 'createdAtCustom',
|
||||
filter: '=',
|
||||
value: 'test',
|
||||
filtersForm: {
|
||||
createdAtCustom: {
|
||||
type: 'datetime',
|
||||
defaultFilter: '=',
|
||||
defaultValue: 'test1',
|
||||
},
|
||||
updatedAtCustom: {
|
||||
type: 'datetime',
|
||||
defaultFilter: '=',
|
||||
defaultValue: 'test2',
|
||||
},
|
||||
size: {
|
||||
type: 'integer',
|
||||
defaultFilter: '=',
|
||||
defaultValue: '0KB',
|
||||
},
|
||||
mime: {
|
||||
type: 'enum',
|
||||
defaultFilter: '_contains',
|
||||
defaultValue: 'image',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(actualFiltersFormKeys).toEqual(expectedFiltersFormKeys);
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return the initialState on reset', () => {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React, { useReducer, useState, useEffect } from 'react';
|
||||
import React, { useReducer, useState, useRef, useEffect } from 'react';
|
||||
import { includes, isEmpty, toString } from 'lodash';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { Header } from '@buffetjs/custom';
|
||||
import { useDebounce, useIsMounted } from '@buffetjs/hooks';
|
||||
import { useDebounce } from '@buffetjs/hooks';
|
||||
import {
|
||||
HeaderSearch,
|
||||
PageFooter,
|
||||
@ -46,7 +46,7 @@ const HomePage = () => {
|
||||
const [searchValue, setSearchValue] = useState(query.get('_q') || '');
|
||||
const { push } = useHistory();
|
||||
const { search } = useLocation();
|
||||
const isMounted = useIsMounted();
|
||||
const isMounted = useRef(true);
|
||||
const { data, dataCount, dataToDelete, isLoading } = reducerState.toJS();
|
||||
const pluginName = formatMessage({ id: getTrad('plugin.name') });
|
||||
const paramsKeys = ['_limit', '_start', '_q', '_sort'];
|
||||
@ -59,12 +59,11 @@ const HomePage = () => {
|
||||
}, [debouncedSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isMounted) {
|
||||
fetchListData();
|
||||
}
|
||||
|
||||
return () => (isMounted.current = false);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [search, isMounted]);
|
||||
}, [search]);
|
||||
|
||||
const deleteMedia = async id => {
|
||||
const requestURL = getRequestUrl(`files/${id}`);
|
||||
@ -74,7 +73,7 @@ const HomePage = () => {
|
||||
method: 'DELETE',
|
||||
});
|
||||
} catch (err) {
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
strapi.notification.error('notification.error');
|
||||
}
|
||||
}
|
||||
@ -85,7 +84,7 @@ const HomePage = () => {
|
||||
|
||||
const [data, count] = await Promise.all([fetchData(), fetchDataCount()]);
|
||||
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
dispatch({
|
||||
type: 'GET_DATA_SUCCEEDED',
|
||||
data,
|
||||
@ -105,7 +104,7 @@ const HomePage = () => {
|
||||
|
||||
return Promise.resolve(data);
|
||||
} catch (err) {
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
dispatch({ type: 'GET_DATA_ERROR' });
|
||||
strapi.notification.error('notification.error');
|
||||
}
|
||||
@ -124,7 +123,7 @@ const HomePage = () => {
|
||||
|
||||
return Promise.resolve(count);
|
||||
} catch (err) {
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
dispatch({ type: 'GET_DATA_ERROR' });
|
||||
strapi.notification.error('notification.error');
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useReducer, useRef } from 'react';
|
||||
import { Header, Inputs } from '@buffetjs/custom';
|
||||
import { useIsMounted } from '@buffetjs/hooks';
|
||||
import { isEqual } from 'lodash';
|
||||
import { LoadingIndicatorPage, useGlobalContext, request } from 'strapi-helper-plugin';
|
||||
|
||||
@ -16,7 +15,7 @@ const SettingsPage = () => {
|
||||
const { formatMessage } = useGlobalContext();
|
||||
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
|
||||
const { initialData, isLoading, modifiedData } = reducerState.toJS();
|
||||
const isMounted = useIsMounted();
|
||||
const isMounted = useRef(true);
|
||||
const getDataRef = useRef();
|
||||
const abortController = new AbortController();
|
||||
|
||||
@ -25,7 +24,7 @@ const SettingsPage = () => {
|
||||
const { signal } = abortController;
|
||||
const { data } = await request(getRequestUrl('settings', { method: 'GET', signal }));
|
||||
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
dispatch({
|
||||
type: 'GET_DATA_SUCCEEDED',
|
||||
data,
|
||||
@ -37,15 +36,14 @@ const SettingsPage = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isMounted) {
|
||||
getDataRef.current();
|
||||
}
|
||||
|
||||
return () => {
|
||||
abortController.abort();
|
||||
isMounted.current = false;
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isMounted]);
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
@ -54,7 +52,7 @@ const SettingsPage = () => {
|
||||
body: modifiedData,
|
||||
});
|
||||
|
||||
if (isMounted) {
|
||||
if (isMounted.current) {
|
||||
dispatch({
|
||||
type: 'SUBMIT_SUCCEEDED',
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user