feat: Search and filters added
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
filterMessages,
|
||||
sortKeys,
|
||||
sortMessages,
|
||||
sortFunctions,
|
||||
} from './utils';
|
||||
|
||||
export const state = {
|
||||
@@ -43,7 +44,43 @@ export const searchAndSortHooks = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const videoListHooks = ({ videos }) => {
|
||||
export const filterListBySearch = ({ searchString, videoList }) => (
|
||||
videoList.filter(({ displayName }) => displayName.toLowerCase().includes(searchString.toLowerCase()))
|
||||
);
|
||||
|
||||
export const filterListByStatus = ({ statusFilter, videoList }) => {
|
||||
if (statusFilter === filterKeys.videoStatus) {
|
||||
return videoList;
|
||||
}
|
||||
return videoList.filter(({ status }) => status === statusFilter);
|
||||
};
|
||||
|
||||
export const filterListByHideSelectedCourse = ({ videoList }) => (
|
||||
// TODO Missing to implement this
|
||||
videoList
|
||||
);
|
||||
|
||||
export const filterList = ({
|
||||
sortBy,
|
||||
filterBy,
|
||||
searchString,
|
||||
videos,
|
||||
}) => {
|
||||
let filteredList = module.filterListBySearch({
|
||||
searchString,
|
||||
videoList: videos,
|
||||
});
|
||||
filteredList = module.filterListByStatus({
|
||||
statusFilter: filterBy,
|
||||
videoList: filteredList,
|
||||
});
|
||||
filteredList = module.filterListByHideSelectedCourse({
|
||||
videoList: filteredList,
|
||||
});
|
||||
return filteredList.sort(sortFunctions[sortBy in sortKeys ? sortKeys[sortBy] : sortKeys.dateNewest]);
|
||||
};
|
||||
|
||||
export const videoListHooks = ({ searchSortProps, videos }) => {
|
||||
const [highlighted, setHighlighted] = module.state.highlighted(null);
|
||||
const [
|
||||
showSelectVideoError,
|
||||
@@ -53,7 +90,7 @@ export const videoListHooks = ({ videos }) => {
|
||||
showSizeError,
|
||||
setShowSizeError,
|
||||
] = module.state.showSizeError(false);
|
||||
const filteredList = videos; // TODO missing filters and sort
|
||||
const filteredList = module.filterList({ ...searchSortProps, videos });
|
||||
return {
|
||||
galleryError: {
|
||||
show: showSelectVideoError,
|
||||
@@ -118,7 +155,7 @@ export const buildVideos = ({ rawVideos }) => {
|
||||
|
||||
export const videoHooks = ({ videos }) => {
|
||||
const searchSortProps = module.searchAndSortHooks();
|
||||
const videoList = module.videoListHooks({ videos });
|
||||
const videoList = module.videoListHooks({ searchSortProps, videos });
|
||||
const {
|
||||
galleryError,
|
||||
galleryProps,
|
||||
|
||||
134
src/editors/containers/VideoGallery/hooks.test.js
Normal file
134
src/editors/containers/VideoGallery/hooks.test.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import * as hooks from './hooks';
|
||||
import { filterKeys, sortKeys } from './utils';
|
||||
import { MockUseState } from '../../../testUtils';
|
||||
import { keyStore } from '../../utils';
|
||||
|
||||
jest.mock('react', () => ({
|
||||
...jest.requireActual('react'),
|
||||
useRef: jest.fn(val => ({ current: val })),
|
||||
useEffect: jest.fn(),
|
||||
useCallback: (cb, prereqs) => ({ cb, prereqs }),
|
||||
}));
|
||||
|
||||
jest.mock('react-redux', () => {
|
||||
const dispatchFn = jest.fn();
|
||||
return {
|
||||
...jest.requireActual('react-redux'),
|
||||
dispatch: dispatchFn,
|
||||
useDispatch: jest.fn(() => dispatchFn),
|
||||
};
|
||||
});
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
const hookKeys = keyStore(hooks);
|
||||
let hook;
|
||||
const testValue = 'testVALUEVALID';
|
||||
|
||||
describe('VideoGallery hooks', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('using state', () => {
|
||||
beforeEach(() => { state.mock(); });
|
||||
afterEach(() => { state.restore(); });
|
||||
|
||||
describe('searchAndSortHooks', () => {
|
||||
beforeEach(() => {
|
||||
hook = hooks.searchAndSortHooks();
|
||||
});
|
||||
it('returns searchString value, initialized to an empty string', () => {
|
||||
expect(state.stateVals.searchString).toEqual(hook.searchString);
|
||||
expect(state.stateVals.searchString).toEqual('');
|
||||
});
|
||||
it('returns highlighted value, initialized to dateNewest', () => {
|
||||
expect(state.stateVals.sortBy).toEqual(hook.sortBy);
|
||||
expect(state.stateVals.sortBy).toEqual(sortKeys.dateNewest);
|
||||
});
|
||||
test('onSearchChange sets searchString with event target value', () => {
|
||||
hook.onSearchChange({ target: { value: testValue } });
|
||||
expect(state.setState.searchString).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
test('clearSearchString sets search string to empty string', () => {
|
||||
hook.clearSearchString();
|
||||
expect(state.setState.searchString).toHaveBeenCalledWith('');
|
||||
});
|
||||
test('onSortClick takes a key and returns callback to set sortBY to that key', () => {
|
||||
hook.onSortClick(testValue);
|
||||
expect(state.setState.sortBy).not.toHaveBeenCalled();
|
||||
hook.onSortClick(testValue)();
|
||||
expect(state.setState.sortBy).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
});
|
||||
describe('filterListBySearch', () => {
|
||||
const matching = [
|
||||
'test',
|
||||
'TEst',
|
||||
'eeees',
|
||||
'essSSSS',
|
||||
];
|
||||
const notMatching = ['bad', 'other', 'bad stuff'];
|
||||
const searchString = 'eS';
|
||||
test('returns list filtered lowercase by displayName', () => {
|
||||
const filter = jest.fn(cb => ({ filter: cb }));
|
||||
hook = hooks.filterListBySearch({ searchString, videoList: { filter } });
|
||||
expect(filter).toHaveBeenCalled();
|
||||
const [[filterCb]] = filter.mock.calls;
|
||||
matching.forEach(val => expect(filterCb({ displayName: val })).toEqual(true));
|
||||
notMatching.forEach(val => expect(filterCb({ displayName: val })).toEqual(false));
|
||||
});
|
||||
});
|
||||
describe('imgListHooks outputs', () => {
|
||||
const props = {
|
||||
searchSortProps: { searchString: 'Es', sortBy: sortKeys.dateNewest, filterBy: filterKeys.videoStatus },
|
||||
videos: [
|
||||
{
|
||||
displayName: 'sOmEuiMAge',
|
||||
staTICUrl: '/assets/sOmEuiMAge',
|
||||
id: 'sOmEuiMAgeURl',
|
||||
},
|
||||
],
|
||||
};
|
||||
const filterList = (args) => ({ filterList: args });
|
||||
const load = () => {
|
||||
jest.spyOn(hooks, hookKeys.filterList).mockImplementationOnce(filterList);
|
||||
hook = hooks.videoListHooks(props);
|
||||
};
|
||||
beforeEach(() => {
|
||||
load();
|
||||
});
|
||||
describe('galleryProps', () => {
|
||||
it('returns highlighted value, initialized to null', () => {
|
||||
expect(hook.galleryProps.highlighted).toEqual(state.stateVals.highlighted);
|
||||
expect(state.stateVals.highlighted).toEqual(null);
|
||||
});
|
||||
test('onHighlightChange sets highlighted with event target value', () => {
|
||||
hook.galleryProps.onHighlightChange({ target: { value: testValue } });
|
||||
expect(state.setState.highlighted).toHaveBeenCalledWith(testValue);
|
||||
});
|
||||
test('displayList returns filterListhook called with searchSortProps and videos', () => {
|
||||
expect(hook.galleryProps.displayList).toEqual(filterList({
|
||||
...props.searchSortProps,
|
||||
videos: props.videos,
|
||||
}));
|
||||
});
|
||||
});
|
||||
describe('galleryError', () => {
|
||||
test('show is initialized to false and returns properly', () => {
|
||||
const show = 'sHOWSelectiRROr';
|
||||
expect(hook.galleryError.show).toEqual(false);
|
||||
state.mockVal(state.keys.showSelectVideoError, show);
|
||||
hook = hooks.videoListHooks(props);
|
||||
expect(hook.galleryError.show).toEqual(show);
|
||||
});
|
||||
test('set sets showSelectVideoError to true', () => {
|
||||
hook.galleryError.set();
|
||||
expect(state.setState.showSelectVideoError).toHaveBeenCalledWith(true);
|
||||
});
|
||||
test('dismiss sets showSelectVideoError to false', () => {
|
||||
hook.galleryError.dismiss();
|
||||
expect(state.setState.showSelectVideoError).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -37,6 +37,27 @@ export const filterMessages = StrictDict({
|
||||
failed: messages[messageKeys.filterByVideoStatusFailed],
|
||||
});
|
||||
|
||||
export const sortFunctions = StrictDict({
|
||||
dateNewest: (a, b) => b.dateAdded - a.dateAdded,
|
||||
dateOldest: (a, b) => a.dateAdded - b.dateAdded,
|
||||
nameAscending: (a, b) => {
|
||||
const nameA = a.displayName.toLowerCase();
|
||||
const nameB = b.displayName.toLowerCase();
|
||||
if (nameA < nameB) { return -1; }
|
||||
if (nameB < nameA) { return 1; }
|
||||
return b.dateAdded - a.dateAdded;
|
||||
},
|
||||
nameDescending: (a, b) => {
|
||||
const nameA = a.displayName.toLowerCase();
|
||||
const nameB = b.displayName.toLowerCase();
|
||||
if (nameA < nameB) { return 1; }
|
||||
if (nameB < nameA) { return -1; }
|
||||
return b.dateAdded - a.dateAdded;
|
||||
},
|
||||
durationShortest: (a, b) => a.duration - b.duration,
|
||||
durationLongest: (a, b) => b.duration - a.duration,
|
||||
});
|
||||
|
||||
export const acceptedImgKeys = StrictDict({
|
||||
mp4: '.mp4',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user