Skip to content

Commit

Permalink
A favorite icon will let the authenticated user add the resource to h…
Browse files Browse the repository at this point in the history
…is favorites (#214)
  • Loading branch information
luorlandini authored Jun 25, 2021
1 parent 711f72e commit 8a02564
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 35 deletions.
15 changes: 15 additions & 0 deletions geonode_mapstore_client/client/js/actions/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ export const SET_RESOURCE_PERMISSIONS = 'GEONODE:SET_RESOURCE_PERMISSIONS';
export const EDIT_TITLE_RESOURCE = 'GEONODE:EDIT_TITLE_RESOURCE';
export const EDIT_ABSTRACT_RESOURCE = 'GEONODE:EDIT_ABSTRACT_RESOURCE';
export const EDIT_THUMBNAIL_RESOURCE = 'GEONODE:EDIT_THUMBNAIL_RESOURCE';
export const SET_FAVOURITE_RESOURCE = 'GEONODE:SET_FAVOURITE_RESOURCE';

export const SET_SELECTED_LAYER_PERMISSIONS = "GEONODE:SET_SELECTED_LAYER_PERMISSIONS";


/**
* Actions for GeoNode resource
* store information of the resource in use
Expand Down Expand Up @@ -174,3 +176,16 @@ export function setSelectedLayerPermissions(permissions) {
permissions
};
}

/**
* Set the resource favourite field (trigger epic gnSaveFavouriteContent)
* @memberof actions.gnresource
* @param {bool} favourite resource data field
*/
export function setFavouriteResource(favourite) {

return {
type: SET_FAVOURITE_RESOURCE,
favourite
};
}
7 changes: 7 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 @@ -243,6 +243,13 @@ export const getDocumentsByDocType = (docType = 'image', {
}));
};


export const setFavouriteResource = (pk, favourite) => {
const request = favourite ? axios.post : axios.delete;
return request(parseDevHostname(`${endpoints[RESOURCES]}/${pk}/favorite`))
.then(({ data }) => data );
};

export const getResourceByPk = (pk) => {
return axios.get(parseDevHostname(`${endpoints[RESOURCES]}/${pk}`))
.then(({ data }) => data.resource);
Expand Down
4 changes: 3 additions & 1 deletion geonode_mapstore_client/client/js/apps/gn-home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import gnsearch from '@js/reducers/gnsearch';
import gnresource from '@js/reducers/gnresource';
import gnsearchEpics from '@js/epics/gnsearch';
import gnlocaleEpics from '@js/epics/gnlocale';
import gnsaveEpics from '@js/epics/gnsave';

import {
getConfiguration,
Expand Down Expand Up @@ -108,7 +109,8 @@ Promise.all([
},
appEpics: {
...gnsearchEpics,
...gnlocaleEpics
...gnlocaleEpics,
...gnsaveEpics
},
geoNodeConfiguration
});
Expand Down
58 changes: 36 additions & 22 deletions geonode_mapstore_client/client/js/components/home/DetailsPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,29 @@ import {
getUserName,
getResourceTypesInfo
} from '@js/utils/GNSearchUtils';

import debounce from 'lodash/debounce';
import CopyToClipboardCmp from 'react-copy-to-clipboard';
import url from 'url';
import {TextEditable, ThumbnailEditable} from '@js/components/ContentsEditable/';
import { TextEditable, ThumbnailEditable } from '@js/components/ContentsEditable/';

const CopyToClipboard = tooltip(CopyToClipboardCmp);

const EditTitle = ({title, onEdit}) => {
const EditTitle = ({ title, onEdit }) => {
return (
<div className="editContainer">
<h1><TextEditable onEdit={ onEdit } text={title} /></h1>
<h1><TextEditable onEdit={onEdit} text={title} /></h1>
</div>);
};

const EditAbstract = ({abstract, onEdit}) => (
const EditAbstract = ({ abstract, onEdit }) => (
<div className="editContainer">
<TextEditable onEdit={ onEdit } text={abstract} />
<TextEditable onEdit={onEdit} text={abstract} />
</div>

);


const EditThumbnail = ({image, onEdit}) => (
const EditThumbnail = ({ image, onEdit }) => (
<div className="editContainer imagepreview">
<ThumbnailEditable onEdit={onEdit} defaultImage={image} />
</div>
Expand Down Expand Up @@ -99,10 +99,12 @@ function DetailsPanel({
editAbstract,
editThumbnail,
activeEditMode,
closePanel
closePanel,
favourite,
onFavourite,
enableFavourite
}) {


const [editModeTitle, setEditModeTitle] = useState(false);
const [editModeAbstract, setEditModeAbstract] = useState(false);

Expand Down Expand Up @@ -137,6 +139,9 @@ function DetailsPanel({
}, 700);
};

const handleFavourite = () => {
onFavourite(!favourite);
};

const types = getTypesInfo();
const {
Expand All @@ -147,7 +152,6 @@ function DetailsPanel({
} = resource && (types[resource.doc_type] || types[resource.resource_type]) || {};
const embedUrl = resource?.embed_url && formatEmbedUrl(resource);
const detailUrl = resource?.pk && formatDetailUrl(resource);

return (
<div
ref={detailsContainerNode}
Expand Down Expand Up @@ -176,7 +180,7 @@ function DetailsPanel({
alignItems: 'center',
justifyContent: 'center'
}}>
<FaIcon name={icon}/>
<FaIcon name={icon} />
</div>
{embedUrl && !editThumbnail
? <iframe
Expand All @@ -198,7 +202,7 @@ function DetailsPanel({
top: 0,
left: 0,
backgroundColor: 'inherit'
}}/> )
}} />)
}
{loading && <div
className="gn-details-panel-preview-loader"
Expand All @@ -216,7 +220,7 @@ function DetailsPanel({
<span className="sr-only">Loading resource detail...</span>
</Spinner>
</div>}
</div> }
</div>}

{activeEditMode && editThumbnail && <div className="gn-details-panel-preview inediting"> <EditThumbnail onEdit={editThumbnail} image={resource?.thumbnail_url} /> </div>}

Expand All @@ -225,19 +229,29 @@ function DetailsPanel({
<div className="gn-details-panel-title" >

{!editModeTitle && <h1>
{ icon && <><FaIcon name={icon}/></>}
{ resource?.title }
{icon && <><FaIcon name={icon} /></>}
{resource?.title}
</h1>
}
{ activeEditMode && !editModeTitle && <span className="inEdit" onClick={handleEditModeTitle} ><FaIcon name={'edit'}/></span>}
{activeEditMode && !editModeTitle && <span className="inEdit" onClick={handleEditModeTitle} ><FaIcon name={'edit'} /></span>}


{editModeTitle && <><h1><EditTitle title={resource?.title} onEdit={editTitle} />
</h1>
<span className="inEdit" onClick={handleEditModeTitle} ><FaIcon name={'check-circle'}/></span></>
<span className="inEdit" onClick={handleEditModeTitle} ><FaIcon name={'check-circle'} /></span></>
}
{
<div className="gn-details-panel-tools">
{
enableFavourite &&
<Button
variant="default"
onClick={debounce(handleFavourite, 500)}>
<FaIcon stylePrefix={favourite ? `fa` : `far`} name="star" />
</Button>
}


{detailUrl && <CopyToClipboard
tooltipPosition="top"
tooltipId={
Expand All @@ -257,7 +271,7 @@ function DetailsPanel({
variant="default"
href={detailUrl}
rel="noopener noreferrer">
<Message msgId={`gnhome.view${name || ''}`}/>
<Message msgId={`gnhome.view${name || ''}`} />
</Button>}
</div>
}
Expand All @@ -273,14 +287,14 @@ function DetailsPanel({
}
})}>{getUserName(resource.owner)}</a></>}
{(resource?.date_type && resource?.date)
&& <>{' '}/{' '}{ moment(resource.date).format('MMMM Do YYYY')}</>}
&& <>{' '}/{' '}{moment(resource.date).format('MMMM Do YYYY')}</>}
</p>
}
<p>
{ activeEditMode && !editModeAbstract && <span className="inEdit" onClick={handleEditModeAbstract} ><FaIcon name={'edit'}/></span>}
{activeEditMode && !editModeAbstract && <span className="inEdit" onClick={handleEditModeAbstract} ><FaIcon name={'edit'} /></span>}
<div className="gn-details-panel-description">
{editModeAbstract && <>
<span className="inEdit" onClick={handleEditModeAbstract} ><FaIcon name={'check-circle'}/></span>
<span className="inEdit" onClick={handleEditModeAbstract} ><FaIcon name={'check-circle'} /></span>
<EditAbstract abstract={resource?.abstract} onEdit={editAbstract} />
</>
}
Expand All @@ -294,7 +308,7 @@ function DetailsPanel({

<p>
{resource?.category?.identifier && <div>
<Message msgId="gnhome.category"/>:{' '}
<Message msgId="gnhome.category" />:{' '}
<a href={formatHref({
query: {
'filter{category.identifier.in}': resource.category.identifier
Expand Down
5 changes: 3 additions & 2 deletions geonode_mapstore_client/client/js/components/home/FaIcon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import React from 'react';
function FaIcon({
name,
className,
style
style,
stylePrefix = 'fa'
}) {
return <i className={`fa fa-${name}${className ? ` ${className}` : ''}`} style={style}/>;
return <i className={`${stylePrefix} fa-${name}${className ? ` ${className}` : ''}`} style={style}/>;
}

FaIcon.defaultProps = {};
Expand Down
31 changes: 28 additions & 3 deletions geonode_mapstore_client/client/js/epics/gnsave.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ import {
resourceLoading,
setResource,
resourceError,
updateResourceProperties
updateResourceProperties,
SET_FAVOURITE_RESOURCE
} from '@js/actions/gnresource';
import {
getResourceByPk,
createGeoStory,
updateGeoStory
updateGeoStory,
setFavouriteResource
} from '@js/api/geonode/v2';
import { parseDevHostname } from '@js/utils/APIUtils';
import uuid from 'uuid';
Expand Down Expand Up @@ -207,8 +209,31 @@ export const gnUpdateResource = (action$, store) =>
.startWith(resourceLoading());
});

export const gnSaveFavouriteContent = (action$, store) =>
action$.ofType(SET_FAVOURITE_RESOURCE)
.switchMap((action) => {
const state = store.getState();
const pk = state?.gnresource?.data.pk;
const favourite = action.favourite;
return Observable
.defer(() => setFavouriteResource(pk, favourite))
.switchMap(() => {
return Observable.of(
updateResourceProperties({
'favourite': favourite
})
);
})
.catch((error) => {
return Observable.of(resourceError(error.data || error.message));
});

});


export default {
gnSaveContent,
gnUpdateResource,
gnSaveDirectContent
gnSaveDirectContent,
gnSaveFavouriteContent
};
1 change: 0 additions & 1 deletion geonode_mapstore_client/client/js/reducers/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ function gnresource(state = {selectedLayerPermissions: [], data: {}}, action) {
};
}


case SET_SELECTED_LAYER_PERMISSIONS:
return {
...state,
Expand Down
19 changes: 15 additions & 4 deletions geonode_mapstore_client/client/js/routes/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ import {
loadFeaturedResources
} from '@js/actions/gnsearch';

import { setFavouriteResource
} from '@js/actions/gnresource';

import {
hashLocationToHref,
getFilterById
Expand Down Expand Up @@ -119,10 +122,15 @@ const ConnectedFeatureList = connect(

const ConnectedDetailsPanel = connect(
createSelector([
state => state?.gnresource?.loading || false
], (loading) => ({
loading
}))
state => state?.gnresource?.loading || false,
state => state?.gnresource?.data?.favourite || false
], (loading, favourite) => ({
loading,
favourite
})),
{
onFavourite: setFavouriteResource
}
)(DetailsPanel);

const suggestionsRequestTypes = {
Expand Down Expand Up @@ -380,6 +388,8 @@ function Home({
const isHeroVisible = !hideHero && inView;
const stickyFiltersMaxHeight = (window.innerHeight - dimensions.brandNavbarHeight - dimensions.actionNavbarNodeHeight - dimensions.footerNodeHeight);
const filterFormTop = dimensions.brandNavbarHeight + dimensions.actionNavbarNodeHeight;


return (
<div className={`gn-home`}>
<MetaTags
Expand Down Expand Up @@ -489,6 +499,7 @@ function Home({
: undefined}
column={ hideHero &&
<ConnectedDetailsPanel
enableFavourite={!!user}
resource={resource}
linkHref={hrefDetailPanel}
formatHref={handleFormatHref}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,8 @@
},
{
"type": "link",
"href": "/favorite/list/",
"labelId": "gnhome.favorites"
"href": "/favourite/list/",
"labelId": "gnhome.favourites"
},
{
"type": "link",
Expand Down

0 comments on commit 8a02564

Please sign in to comment.