-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Dashboard: support filtering stories by taxonomy (#11625)
Co-authored-by: Sam Blinde <samantha.blinde@formidable.com> Co-authored-by: Jonny Harris <spacedmonkey@users.noreply.github.com> Co-authored-by: Pascal Birchler <pascalb@google.com>
- Loading branch information
1 parent
d8f8529
commit 8f8319b
Showing
27 changed files
with
1,163 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright 2022 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { useConfig } from '../config'; | ||
|
||
function useTaxonomyApi() { | ||
const { | ||
apiCallbacks: { getTaxonomies, getTaxonomyTerms }, | ||
} = useConfig(); | ||
|
||
return { | ||
api: { | ||
getTaxonomies, | ||
getTaxonomyTerms, | ||
}, | ||
}; | ||
} | ||
|
||
export default useTaxonomyApi; |
134 changes: 134 additions & 0 deletions
134
packages/dashboard/src/app/views/myStories/filters/provider.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* Copyright 2022 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
import { | ||
createContext, | ||
useReducer, | ||
useEffect, | ||
useCallback, | ||
useMemo, | ||
} from '@googleforcreators/react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
/** @typedef {import('react')} Node */ | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import reducer from './reducer'; | ||
import useTaxonomyFilters from './taxonomy/useTaxonomyFilters'; | ||
import * as types from './types'; | ||
|
||
export const filterContext = createContext({ | ||
state: {}, | ||
actions: {}, | ||
}); | ||
|
||
/** | ||
* Keeps track of the current filters state. | ||
* | ||
* Each filter will have its own logic associated with | ||
* initilization and how to query terms. | ||
* | ||
* | ||
* @param {Object} root0 props for the provider | ||
* @param {Node} root0.children the children to be rendered | ||
* @return {Node} React node | ||
*/ | ||
|
||
export default function FiltersProvider({ children }) { | ||
// each filter type will have its own logic for initilizing and querying | ||
const { initializeTaxonomyFilters } = useTaxonomyFilters(); | ||
|
||
const [state, dispatch] = useReducer(reducer, { | ||
filtersLoading: true, | ||
filters: [], | ||
}); | ||
|
||
/** | ||
* Dispatch UPDATE_FILTER with new data for a given filter | ||
* | ||
* @param {string} key key property on one of the filter objects | ||
* @param {Object} value the properties with updated values | ||
* @return {void} | ||
*/ | ||
const updateFilter = useCallback((key, value) => { | ||
dispatch({ type: types.UPDATE_FILTER, payload: { key, value } }); | ||
}, []); | ||
|
||
/** | ||
* Dispatch REGISTER_FILTERS with all the filters data | ||
* | ||
* @param {Array} payload array of filters data | ||
* @return {void} | ||
*/ | ||
const registerFilters = useCallback((value) => { | ||
dispatch({ type: types.REGISTER_FILTERS, payload: { value } }); | ||
}, []); | ||
|
||
/** | ||
* Sets up the shape of the filters data | ||
* and calls registerFilters with all filters. | ||
* | ||
* @return {void} | ||
*/ | ||
const initializeFilters = useCallback(() => { | ||
const filters = initializeTaxonomyFilters(); | ||
|
||
registerFilters(filters); | ||
}, [registerFilters, initializeTaxonomyFilters]); | ||
|
||
/** | ||
* Returns a object where the keys are the filter keys | ||
* and the values are the filterId | ||
* | ||
* @return {Object} | ||
*/ | ||
const getFiltersObject = useCallback(() => { | ||
const filterObj = {}; | ||
for (const filter of state.filters) { | ||
const { key, filterId } = filter; | ||
if (filterId) { | ||
filterObj[key] = filterId; | ||
} | ||
} | ||
return filterObj; | ||
}, [state.filters]); | ||
|
||
const contextValue = useMemo(() => { | ||
return { | ||
state, | ||
actions: { updateFilter, registerFilters, getFiltersObject }, | ||
}; | ||
}, [state, updateFilter, registerFilters, getFiltersObject]); | ||
|
||
useEffect(() => { | ||
initializeFilters(); | ||
}, [initializeFilters]); | ||
|
||
return ( | ||
<filterContext.Provider value={contextValue}> | ||
{children} | ||
</filterContext.Provider> | ||
); | ||
} | ||
|
||
FiltersProvider.propTypes = { | ||
children: PropTypes.node, | ||
}; |
73 changes: 73 additions & 0 deletions
73
packages/dashboard/src/app/views/myStories/filters/reducer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright 2022 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import * as types from './types'; | ||
|
||
/** | ||
* Update the filters state | ||
* | ||
* TODO: May need updating to handle all filter types within the dashboard. | ||
* | ||
* @param {Object} state Current state | ||
* @param {Object} payload Action payload | ||
* @param {string} payload.key Key for associated filter. | ||
* @param {Object} payload.value Value to set on the filter. | ||
* @return {Object} New state | ||
*/ | ||
|
||
const reducer = (state, { type, payload = {} }) => { | ||
switch (type) { | ||
case types.UPDATE_FILTER: { | ||
const { key, value } = payload; | ||
const filter = state.filters.find((f) => f.key === key); | ||
|
||
if (!filter) { | ||
return state; | ||
} | ||
|
||
// remove 'filter-by' value | ||
if (value.filterId && filter?.filterId === value.filterId) { | ||
value.filterId = null; | ||
} | ||
|
||
// replace old filter | ||
const idx = state.filters.indexOf(filter); | ||
const filters = [...state.filters]; | ||
filters[idx] = { ...filter, ...value }; | ||
|
||
return { | ||
...state, | ||
filters, | ||
}; | ||
} | ||
|
||
case types.REGISTER_FILTERS: { | ||
const { value } = payload; | ||
return { | ||
...state, | ||
filtersLoading: false, | ||
filters: value, | ||
}; | ||
} | ||
default: | ||
return state; | ||
} | ||
}; | ||
|
||
export default reducer; |
Oops, something went wrong.