Skip to content

Commit

Permalink
Show Featured Items (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
MuhweziDeo authored Jun 11, 2021
1 parent 6a8d504 commit 24323fb
Show file tree
Hide file tree
Showing 15 changed files with 330 additions and 16 deletions.
33 changes: 32 additions & 1 deletion geonode_mapstore_client/client/js/actions/gnsearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const LOADING_RESOURCES = 'GEONODE_SEARCH:LOADING_RESOURCES';
export const SELECT_RESOURCE = 'GEONODE_SEARCH:SELECT_RESOURCE';
export const REQUEST_RESOURCE = 'GEONODE_SEARCH:REQUEST_RESOURCE';
export const UPDATE_RESOURCES_METADATA = 'GEONODE_SEARCH:UPDATE_RESOURCES_METADATA';
export const SET_FEATURED_RESOURCES = 'GEONODE:SET_FEATURED_RESOURCES';
export const UPDATE_FEATURED_RESOURCES = 'GEONODE_SEARCH:UPDATE_FEATURED_RESOURCES';

export function fetchSuggestions(text) {
return {
Expand Down Expand Up @@ -75,6 +77,34 @@ export function requestResource(pk, ctype) {
};
}


/**
* Actions for GeoNode resource featured items
* set new Featured Resources includes data, page, links
* @name actions.gnsearch
*/
export function setFeaturedResources(data) {
return {
type: SET_FEATURED_RESOURCES,
data
};
}

/**
* Actions for GeoNode resource featured items
* loads new featured resources basing on the action, previous or next
* @param action {string} can be either next or previous
* @param pageSize { number } page_size of items to load defaults to 4;
* @name actions.gnsearch
*/
export function loadFeaturedResources(action, pageSize = 4) {
return {
type: UPDATE_FEATURED_RESOURCES,
action,
pageSize
};
}

export default {
FETCH_SUGGESTIONS,
fetchSuggestions,
Expand All @@ -89,5 +119,6 @@ export default {
LOADING_RESOURCES,
loadingResources,
REQUEST_RESOURCE,
requestResource
requestResource,
setFeaturedResources
};
10 changes: 10 additions & 0 deletions geonode_mapstore_client/client/js/api/geonode/v2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,16 @@ export const getResourcesTotalCount = () => {
});
};

export const getFeaturedResources = (page = 1, page_size = 4) => {
return axios.get(parseDevHostname(endpoints[RESOURCES]), {
params: {
page_size,
page,
'filter{featured}': true
}
}).then(({data}) => data);
};

export const getCategories = ({ q, idIn, ...params }, filterKey = 'categories') => {
return axios.get(parseDevHostname(`${endpoints[CATEGORIES]}`), {
params: {
Expand Down
173 changes: 173 additions & 0 deletions geonode_mapstore_client/client/js/components/home/FeaturedList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Copyright 2020, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import React, { useEffect, useState } from 'react';
import Button from '@js/components/Button';
import Spinner from '@js/components/Spinner';
import HTML from '@mapstore/framework/components/I18N/HTML';
import ResourceCard from '@js/components/home/ResourceCard';
import FaIcon from '@js/components/home/FaIcon';
import { withResizeDetector } from 'react-resize-detector';

const Cards = withResizeDetector(({
resources,
formatHref,
isCardActive,
buildHrefByTemplate,
containerWidth,
width: detectedWidth,
options,
onResize
}) => {

const width = detectedWidth || containerWidth;
const margin = 24;
const size = 320;
const count = Math.floor(width / (size + margin));
const cardWidth = width >= size + margin * 2
? Math.floor((width - margin * count) / count)
: '100%';
useEffect(() => {
onResize(count);
}, [ count ]);
const ulPadding = Math.floor(margin / 2);
const isSingleCard = count === 0 || count === 1;

const gridLayoutSpace = (idx) => {

const gridSpace = isSingleCard
? {
width: width - margin,
margin: ulPadding
}
: {
width: cardWidth,
marginRight: (idx + 1) % count === 0 ? 0 : margin,
marginTop: margin
};

return gridSpace;
};

const containerStyle = isSingleCard
? {
paddingBottom: margin
}
: {
paddingLeft: ulPadding,
paddingBottom: margin
};
return (
<ul
style={containerStyle}
>
{resources.map((resource, idx) => {
return (
<li
key={resource?.pk}
style={(gridLayoutSpace(idx))}
>
<ResourceCard
active={isCardActive(resource)}
data={resource}
formatHref={formatHref}
options={options}
buildHrefByTemplate={buildHrefByTemplate}
layoutCardsStyle="grid"
/>
</li>
);
})}
</ul>
);
});

const FeaturedList = withResizeDetector(({
resources,
loading,
isNextPageAvailable,
formatHref,
isCardActive,
containerStyle,
header,
cardOptions,
buildHrefByTemplate,
isPreviousPageAvailable,
loadFeaturedResources,
onLoad,
width
}) => {

const [count, setCount] = useState();
const nextIconStyles = {
fontSize: '2rem',
...(!isNextPageAvailable || loading ? {color: 'grey', cursor: 'not-allowed'} : {cursor: 'pointer'})
};

const previousIconStyles = {
fontSize: '2rem',
...(!isPreviousPageAvailable || loading ? {color: 'grey', cursor: 'not-allowed'} : {cursor: 'pointer'})};

return (
<div className="gn-card-grid" style={resources.length === 0 ? { display: 'none' } : {}}>
{header}
<div style={{
display: 'flex'
}}>
<div style={{ flex: 1 }}>
<div className="gn-card-grid-container" style={containerStyle}>
<h3><HTML msgId={`gnhome.featuredList`}/></h3>
<Cards
resources={resources}
formatHref={formatHref}
isCardActive={isCardActive}
options={cardOptions}
buildHrefByTemplate={buildHrefByTemplate}
containerWidth={width}
onResize={(cardsCount) => {
onLoad(undefined, cardsCount);
setCount(cardsCount);
}}
/>
<div className="gn-card-grid-pagination featured-list">

<Button size="sm" onClick={() => loadFeaturedResources("previous", count)} disabled={!isPreviousPageAvailable || loading}
aria-hidden="true">
<FaIcon style={previousIconStyles} name="caret-left"/>
</Button>

<div>
{ loading && <Spinner size="sm" animation="border" role="status">
<span className="sr-only">Loading...</span>
</Spinner>}
</div>
<Button size="sm" onClick={() => loadFeaturedResources("next", count)} disabled={!isNextPageAvailable || loading}
aria-hidden="true">
<FaIcon style={nextIconStyles} name="caret-right"/>

</Button>
</div>
</div>
</div>
</div>
</div>
);
});

FeaturedList.defaultProps = {
page: 1,
resources: [],
isNextPageAvailable: false,
loading: false,
formatHref: () => '#',
isCardActive: () => false,
isPreviousPageAvailable: false,
onLoad: () => { }
};

export default FeaturedList;
39 changes: 36 additions & 3 deletions geonode_mapstore_client/client/js/epics/gnsearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
} from '@js/api/geonode/v1';
import {
getResources,
getResourceByPk
getResourceByPk,
getFeaturedResources
} from '@js/api/geonode/v2';
import {
FETCH_SUGGESTIONS,
Expand All @@ -25,7 +26,9 @@ import {
REQUEST_RESOURCE,
updateResources,
loadingResources,
updateResourcesMetadata
updateResourcesMetadata,
setFeaturedResources,
UPDATE_FEATURED_RESOURCES
} from '@js/actions/gnsearch';
import {
resourceLoading,
Expand Down Expand Up @@ -69,6 +72,20 @@ const getParams = (locationSearch = '', params, defaultPage = 1) => {
];
};

const getNextPage = (action, state) => {
if (!action) {
return 1;
}
const currentPage = state.gnsearch?.featuredResources?.page || 1;
const isNextPageAvailable = state.gnsearch?.featuredResources?.isNextPageAvailable;
if (action === 'next' && isNextPageAvailable) {
return currentPage + 1;
}
const isPreviousPageAvailable = state.gnsearch?.featuredResources?.isPreviousPageAvailable;

return isPreviousPageAvailable ? currentPage - 1 : 1;
};

export const gnsFetchSuggestionsEpic = (action$) =>
action$.ofType(FETCH_SUGGESTIONS)
.debounceTime(300)
Expand Down Expand Up @@ -225,9 +242,25 @@ export const gnsSelectResourceEpic = (action$, store) =>
);
});

export const getFeaturedResourcesEpic = (action$, {getState = () => {}}) =>
action$.ofType(UPDATE_FEATURED_RESOURCES)
.switchMap(({action, pageSize}) => {
const page = getNextPage(action, getState());
return Observable.defer( () => getFeaturedResources(page, pageSize))
.switchMap((data) => {
return Observable.of(setFeaturedResources({...data,
isNextPageAvailable: !!data?.links?.next,
isPreviousPageAvailable: !!data?.links.previous, loading: false}));
}).catch((error) => {
return Observable.of(resourceError(error.data || error.message), setFeaturedResources({loading: false}));
}).startWith(setFeaturedResources({loading: true}));
});


export default {
gnsFetchSuggestionsEpic,
gnsSearchResourcesEpic,
gnsSearchResourcesOnLocationChangeEpic,
gnsSelectResourceEpic
gnsSelectResourceEpic,
getFeaturedResourcesEpic
};
16 changes: 14 additions & 2 deletions geonode_mapstore_client/client/js/reducers/gnsearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ import {
SEARCH_RESOURCES,
UPDATE_RESOURCES,
LOADING_RESOURCES,
UPDATE_RESOURCES_METADATA
UPDATE_RESOURCES_METADATA,
SET_FEATURED_RESOURCES
} from '@js/actions/gnsearch';

function gnsearch(state = {
resources: [],
params: {},
previousParams: {},
isFirstRequest: true
isFirstRequest: true,
featuredResources: {
resources: []
}
}, action) {
switch (action.type) {
case UPDATE_SUGGESTIONS: {
Expand Down Expand Up @@ -81,6 +85,14 @@ function gnsearch(state = {
loading: action.loading
};
}
case SET_FEATURED_RESOURCES:
return {
...state,
featuredResources: {
...state.featuredResources,
...action.data
}
};
default:
return state;
}
Expand Down
2 changes: 1 addition & 1 deletion geonode_mapstore_client/client/js/routes/Detail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import Home from '@js/routes/Home';


const DetailRoute = connect(() => ({ hideHero: true, isFilterForm: false })
const DetailRoute = connect(() => ({ hideHero: true, isFilterForm: false, disableFeatured: true })
)((Home));

export default DetailRoute;
Loading

0 comments on commit 24323fb

Please sign in to comment.