diff --git a/package.json b/package.json index 3e0f991ced78fba35d959afa4e5c01f474c885b4..3a1f316cd2b55712c557b34a8bc871cf8ba98ec6 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "@mui/material": "^5.3.0", "@mui/styles": "^5.3.0", "@nosferatu500/react-sortable-tree": "^3.0.5", - "@shakacode/recompose": "^0.30.3", "@turf/buffer": "^6.3.0", "apexcharts": "^3.33.0", "axios": "^0.25.0", diff --git a/src/client/components/SemanticPortal.stories.js b/src/client/components/SemanticPortal.stories.js index 8ef64797c6060e6c6108bbb77d2aa2973dacaf1d..b3b5ea76953b9509de95458f5ec5c6d0f90807d9 100644 --- a/src/client/components/SemanticPortal.stories.js +++ b/src/client/components/SemanticPortal.stories.js @@ -17,7 +17,6 @@ export const basic = () => { // const location = useLocation() // const screenSize = 'lg' // const rootUrlWithLang = '' - // const routeProps = { location } return ( <SemanticPortal /> ) diff --git a/src/client/components/facet_results/FacetResults.js b/src/client/components/facet_results/FacetResults.js index b1fe8e6e1301873722c5107015d24230fa22e935..6d81f144a6c95c1c4097c479fc015fdd24856dfd 100644 --- a/src/client/components/facet_results/FacetResults.js +++ b/src/client/components/facet_results/FacetResults.js @@ -14,7 +14,6 @@ const FacetResults = props => { return ( <> <PerspectiveTabs - routeProps={props.routeProps} tabs={perspective.tabs} screenSize={props.screenSize} layoutConfig={props.layoutConfig} @@ -170,10 +169,6 @@ FacetResults.propTypes = { * Redux action for showing an error */ updateFacetOption: PropTypes.func.isRequired, - /** - * Routing information from React Router. - */ - routeProps: PropTypes.object.isRequired, /** * Perspective config. */ diff --git a/src/client/components/facet_results/FacetedSearchPerspective.js b/src/client/components/facet_results/FacetedSearchPerspective.js index 086a8fccb60dd5b24f14d92c9673af394db49fbb..f21bfe66872c04e9d2a2770e52c23bfd28a05dd0 100644 --- a/src/client/components/facet_results/FacetedSearchPerspective.js +++ b/src/client/components/facet_results/FacetedSearchPerspective.js @@ -9,7 +9,7 @@ const FacetedSearchPerspective = props => { const { portalConfig, layoutConfig, perspective, perspectiveState, facetState, facetStateConstrainSelf, screenSize, rootUrl, apexChartsConfig, networkConfig, - leafletConfig, routeProps + leafletConfig } = props const { facetedSearchHeaderExpanded } = perspectiveState return ( @@ -150,7 +150,6 @@ const FacetedSearchPerspective = props => { updateMapBounds={props.updateMapBounds} sortResults={props.sortResults} showError={props.showError} - routeProps={routeProps} perspective={perspective} animationValue={props.animationValue} animateMap={props.animateMap} diff --git a/src/client/components/facet_results/FederatedResults.js b/src/client/components/facet_results/FederatedResults.js index 65b5968fadf872ce524db23e9ba8ea2c23242fe9..2d5bbf829595130fd68c79838ebf95f4823ba7d1 100644 --- a/src/client/components/facet_results/FederatedResults.js +++ b/src/client/components/facet_results/FederatedResults.js @@ -22,7 +22,6 @@ const FederatedResults = props => { return ( <> <PerspectiveTabs - routeProps={props.routeProps} tabs={perspective.tabs} screenSize={props.screenSize} layoutConfig={layoutConfig} @@ -31,108 +30,95 @@ const FederatedResults = props => { exact path={`${rootUrl}/${perspectiveID}/${searchMode}`} render={() => <Redirect to={`${rootUrl}/${perspectiveID}/${searchMode}/table`} />} /> - <Route - path={`${rootUrl}/${perspectiveID}/${searchMode}/table`} - render={() => - <VirtualizedTable - portalConfig={portalConfig} - list={Immutable.List(props.clientFSResults)} - clientFSState={props.clientFSState} - clientFSSortResults={props.clientFSSortResults} - perspectiveID={perspectiveID} - layoutConfig={layoutConfig} - />} - /> - <Route - path={`${rootUrl}/${perspectiveID}/${searchMode}/map_clusters`} - render={() => - <LeafletMap - portalConfig={portalConfig} - center={mapClusters.center} - zoom={mapClusters.zoom} - results={props.clientFSResults} - leafletMapState={props.leafletMapState} - resultClass='mapClusters' - pageType='clientFSResults' - mapMode='cluster' - createPopUpContent={props.leafletConfig.createPopUpContentNameSampo} - fetchResults={props.fetchResults} - fetchGeoJSONLayers={props.fetchGeoJSONLayers} - clearGeoJSONLayers={props.clearGeoJSONLayers} - fetchByURI={props.fetchByURI} - fetching={false} - showInstanceCountInClusters={false} - updateFacetOption={props.updateFacetOption} - showError={props.showError} - showExternalLayers - layerControlExpanded={layerControlExpanded} - layerConfigs={props.leafletConfig.layerConfigs} - updateMapBounds={props.updateMapBounds} - layoutConfig={layoutConfig} - />} - /> - <Route - path={`${rootUrl}/${perspectiveID}/${searchMode}/map_markers`} - render={() => { - if (props.clientFSResults.length > 500) { - return <ResultInfo message={intl.get('leafletMap.tooManyResults')} /> - } else { - return ( - <LeafletMap - portalConfig={portalConfig} - center={mapMarkers.center} - zoom={mapMarkers.zoom} - results={props.clientFSResults} - leafletMapState={props.leafletMapState} - resultClass='mapMarkers' - pageType='clientFSResults' - mapMode='marker' - createPopUpContent={props.leafletConfig.createPopUpContentNameSampo} - fetchResults={props.fetchResults} - fetchGeoJSONLayers={props.fetchGeoJSONLayers} - clearGeoJSONLayers={props.clearGeoJSONLayers} - fetchByURI={props.fetchByURI} - fetching={false} - showInstanceCountInClusters={false} - updateFacetOption={props.updateFacetOption} - showError={props.showError} - showExternalLayers - layerControlExpanded={layerControlExpanded} - layerConfigs={props.leafletConfig.layerConfigs} - updateMapBounds={props.updateMapBounds} - layoutConfig={layoutConfig} - /> + <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/table`}> + <VirtualizedTable + portalConfig={portalConfig} + list={Immutable.List(props.clientFSResults)} + clientFSState={props.clientFSState} + clientFSSortResults={props.clientFSSortResults} + perspectiveID={perspectiveID} + layoutConfig={layoutConfig} + /> + </Route> + <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/map_clusters`}> + <LeafletMap + portalConfig={portalConfig} + center={mapClusters.center} + zoom={mapClusters.zoom} + results={props.clientFSResults} + leafletMapState={props.leafletMapState} + resultClass='mapClusters' + pageType='clientFSResults' + mapMode='cluster' + createPopUpContent={props.leafletConfig.createPopUpContentNameSampo} + fetchResults={props.fetchResults} + fetchGeoJSONLayers={props.fetchGeoJSONLayers} + clearGeoJSONLayers={props.clearGeoJSONLayers} + fetchByURI={props.fetchByURI} + fetching={false} + showInstanceCountInClusters={false} + updateFacetOption={props.updateFacetOption} + showError={props.showError} + showExternalLayers + layerControlExpanded={layerControlExpanded} + layerConfigs={props.leafletConfig.layerConfigs} + updateMapBounds={props.updateMapBounds} + layoutConfig={layoutConfig} + /> + </Route> + <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/map_markers`}> + {props.clientFSResults.length < 500 + ? ( + <LeafletMap + portalConfig={portalConfig} + center={mapMarkers.center} + zoom={mapMarkers.zoom} + results={props.clientFSResults} + leafletMapState={props.leafletMapState} + resultClass='mapMarkers' + pageType='clientFSResults' + mapMode='marker' + createPopUpContent={props.leafletConfig.createPopUpContentNameSampo} + fetchResults={props.fetchResults} + fetchGeoJSONLayers={props.fetchGeoJSONLayers} + clearGeoJSONLayers={props.clearGeoJSONLayers} + fetchByURI={props.fetchByURI} + fetching={false} + showInstanceCountInClusters={false} + updateFacetOption={props.updateFacetOption} + showError={props.showError} + showExternalLayers + layerControlExpanded={layerControlExpanded} + layerConfigs={props.leafletConfig.layerConfigs} + updateMapBounds={props.updateMapBounds} + layoutConfig={layoutConfig} + /> ) - } - }} - /> - <Route - path={`${rootUrl}/${perspectiveID}/${searchMode}/statistics`} - render={() => - <Pie - portalConfig={portalConfig} - data={props.clientFSResults} - groupBy={props.clientFSState.groupBy} - groupByLabel={props.clientFSState.groupByLabel} - query={props.clientFSState.query} - layoutConfig={layoutConfig} - />} - /> - <Route - path={`${rootUrl}/${perspectiveID}/${searchMode}/download`} - render={() => - <CSVButton - results={props.clientFSResults} - layoutConfig={layoutConfig} - portalConfig={portalConfig} - />} - /> + : <ResultInfo message={intl.get('leafletMap.tooManyResults')} />} + </Route> + <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/statistics`}> + <Pie + portalConfig={portalConfig} + data={props.clientFSResults} + groupBy={props.clientFSState.groupBy} + groupByLabel={props.clientFSState.groupByLabel} + query={props.clientFSState.query} + layoutConfig={layoutConfig} + /> + </Route> + <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/download`}> + <CSVButton + results={props.clientFSResults} + layoutConfig={layoutConfig} + portalConfig={portalConfig} + /> + </Route> + </> ) } FederatedResults.propTypes = { - routeProps: PropTypes.object.isRequired, perspective: PropTypes.object.isRequired, screenSize: PropTypes.string.isRequired, clientFSState: PropTypes.object.isRequired, diff --git a/src/client/components/facet_results/FederatedSearchPerspective.js b/src/client/components/facet_results/FederatedSearchPerspective.js index 0674aea0d009637b00a7c0f615364cbbe40950ae..5589a6d99b58b97c8f4198d13a785546950d3518 100644 --- a/src/client/components/facet_results/FederatedSearchPerspective.js +++ b/src/client/components/facet_results/FederatedSearchPerspective.js @@ -8,7 +8,7 @@ const FederatedSearchPerspective = props => { const { portalConfig, layoutConfig, perspective, screenSize, rootUrl, apexChartsConfig, networkConfig, - leafletConfig, routeProps + leafletConfig } = props const MainClientFS = lazy(() => import(`../../components/perspectives/${portalConfig.portalID}/MainClientFS`)) @@ -103,7 +103,6 @@ const FederatedSearchPerspective = props => { portalConfig={portalConfig} layoutConfig={layoutConfig} perspective={perspective} - routeProps={routeProps} screenSize={screenSize} clientFSState={props.clientFSState} clientFSResults={props.clientFSResults} diff --git a/src/client/components/facet_results/ReactVirtualizedTable.js b/src/client/components/facet_results/ReactVirtualizedTable.js index 2593116627baafc754a3a335ddecc0be2e763f63..cd80f2de8ae1cc0c3cfd0f3b88ee23a2c15a68d8 100644 --- a/src/client/components/facet_results/ReactVirtualizedTable.js +++ b/src/client/components/facet_results/ReactVirtualizedTable.js @@ -187,7 +187,7 @@ MuiVirtualizedTable.propTypes = { const VirtualizedTable = withStyles(styles)(MuiVirtualizedTable) const rootStyle = { - height: 'calc(100% - 80px)', + height: 'calc(100% - 58px)', fontFamily: 'Roboto' } @@ -200,7 +200,7 @@ const tableContainer = { const progressContainerStyle = { width: '100%', - height: 'calc(100% - 80px)', + height: 'calc(100% - 58px)', display: 'flex', alignItems: 'center', justifyContent: 'center' diff --git a/src/client/components/facet_results/ResultClassRoute.js b/src/client/components/facet_results/ResultClassRoute.js index 200b090d977fede203058994f5810cae0ddca65f..8e0cadc4efd8c6007444a3333fccd6b59fd540c5 100644 --- a/src/client/components/facet_results/ResultClassRoute.js +++ b/src/client/components/facet_results/ResultClassRoute.js @@ -1,6 +1,6 @@ import React, { lazy } from 'react' import intl from 'react-intl-universal' -import { Route } from 'react-router-dom' +import { Route, useLocation } from 'react-router-dom' import { has } from 'lodash' // import LineChartSotasurmat from '../perspectives/sotasurmat/LineChartSotasurmat' const ResultTable = lazy(() => import('./ResultTable')) @@ -52,40 +52,32 @@ const ResultClassRoute = props => { switch (component) { case 'ResultTable': routeComponent = ( - <Route - path={path} - render={routeProps => - <ResultTable - portalConfig={portalConfig} - perspectiveConfig={perspective} - data={perspectiveState} - facetUpdateID={facetState.facetUpdateID} - resultClass={resultClass} - facetClass={facetClass} - fetchPaginatedResults={props.fetchPaginatedResults} - updatePage={props.updatePage} - updateRowsPerPage={props.updateRowsPerPage} - sortResults={props.sortResults} - routeProps={routeProps} - rootUrl={rootUrl} - layoutConfig={layoutConfig} - />} + <ResultTable + portalConfig={portalConfig} + perspectiveConfig={perspective} + data={perspectiveState} + facetUpdateID={facetState.facetUpdateID} + resultClass={resultClass} + facetClass={facetClass} + fetchPaginatedResults={props.fetchPaginatedResults} + updatePage={props.updatePage} + updateRowsPerPage={props.updateRowsPerPage} + sortResults={props.sortResults} + rootUrl={rootUrl} + layoutConfig={layoutConfig} + location={useLocation()} /> ) break case 'ReactVirtualizedList': routeComponent = ( - <Route - path={path} - render={routeProps => - <ReactVirtualizedList - resultClass={resultClass} - facetClass={facetClass} - fetchResults={props.fetchResults} - perspectiveState={perspectiveState} - facetUpdateID={facetState.facetUpdateID} - layoutConfig={layoutConfig} - />} + <ReactVirtualizedList + resultClass={resultClass} + facetClass={facetClass} + fetchResults={props.fetchResults} + perspectiveState={perspectiveState} + facetUpdateID={facetState.facetUpdateID} + layoutConfig={layoutConfig} /> ) break @@ -116,12 +108,7 @@ const ResultClassRoute = props => { data: perspectiveState.instanceTableData } } - routeComponent = ( - <Route - path={path} - render={routeProps => <InstancePageTable {...instanceTableProps} />} - /> - ) + routeComponent = <InstancePageTable {...instanceTableProps} /> break } case 'LeafletMap': { @@ -183,13 +170,7 @@ const ResultClassRoute = props => { if (pageType === 'instancePage') { leafletProps.uri = perspectiveState.instanceTableData.id } - routeComponent = ( - <Route - path={path} - render={() => - <LeafletMap {...leafletProps} />} - /> - ) + routeComponent = <LeafletMap {...leafletProps} /> break } case 'Deck': { @@ -238,12 +219,7 @@ const ResultClassRoute = props => { instanceVariable } } - routeComponent = ( - <Route - path={path} - render={() => <Deck {...deckProps} />} - /> - ) + routeComponent = <Deck {...deckProps} /> break } case 'ApexCharts': { @@ -267,13 +243,7 @@ const ResultClassRoute = props => { facetUpdateID: facetState ? facetState.facetUpdateID : null, fetchData: props.fetchResults } - routeComponent = ( - <Route - path={path} - render={() => - <ApexCharts {...apexProps} />} - /> - ) + routeComponent = <ApexCharts {...apexProps} /> break } // case 'LineChartSotasurmat': { @@ -282,16 +252,9 @@ const ResultClassRoute = props => { // facetUpdateID: facetState.facetUpdateID, // fetchResults: props.fetchResults, // updatePage: props.updatePage, - // routeProps: props.routeProps, // resultCount: perspectiveState.resultCount // } - // routeComponent = ( - // <Route - // path={path} - // render={() => - // <LineChartSotasurmat {...lineChartProps} />} - // /> - // ) + // routeComponent = <LineChartSotasurmat {...lineChartProps} /> // break // } case 'Network': { @@ -332,13 +295,7 @@ const ResultClassRoute = props => { if (pageType === 'instancePage') { networkProps.uri = perspectiveState.instanceTableData.id } - routeComponent = ( - <Route - path={path} - render={() => - <Network {...networkProps} />} - /> - ) + routeComponent = <Network {...networkProps} /> break } case 'VideoPage': { @@ -351,17 +308,10 @@ const ResultClassRoute = props => { perspectiveState, properties: getVisibleRows(perspectiveState), localID: props.localID, - routeProps: props.routeProps, videoPlayerState: props.videoPlayerState, updateVideoPlayerTime: props.updateVideoPlayerTime } - routeComponent = ( - <Route - path={path} - render={() => - <VideoPage {...videoPageProps} />} - /> - ) + routeComponent = <VideoPage {...videoPageProps} /> break } case 'TemporalMap': { @@ -378,61 +328,41 @@ const ResultClassRoute = props => { animateMap: props.animateMap, facetUpdateID: facetState.facetUpdateID } - routeComponent = ( - <Route - path={path} - render={() => - <TemporalMap {...temporalMapProps} />} - /> - ) + routeComponent = <TemporalMap {...temporalMapProps} /> break } case 'WordCloud': { const wordCloudProps = { data: perspectiveState.instanceTableData[resultClassConfig.wordCloudProperty] } - routeComponent = ( - <Route - path={path} - render={() => - <WordCloud {...wordCloudProps} />} - /> - ) + routeComponent = <WordCloud {...wordCloudProps} /> break } case 'Export': { const { pageType = 'facetResults' } = resultClassConfig const exportResultClass = resultClassConfig.resultClass routeComponent = ( - <Route - path={path} - render={routeProps => - <Export - portalConfig={portalConfig} - data={perspectiveState} - resultClass={exportResultClass} - facetClass={facetClass} - pageType={pageType} - fetchPaginatedResults={props.fetchPaginatedResults} - updatePage={props.updatePage} - layoutConfig={props.layoutConfig} - />} + <Export + portalConfig={portalConfig} + data={perspectiveState} + resultClass={exportResultClass} + facetClass={facetClass} + pageType={pageType} + fetchPaginatedResults={props.fetchPaginatedResults} + updatePage={props.updatePage} + layoutConfig={props.layoutConfig} /> ) break } case 'ExportCSV': { routeComponent = ( - <Route - path={path} - render={routeProps => - <ExportCSV - resultClass={resultClass} - facetClass={facetClass} - facetUpdateID={facetState.facetUpdateID} - facets={facetState.facets} - layoutConfig={layoutConfig} - />} + <ExportCSV + resultClass={resultClass} + facetClass={facetClass} + facetUpdateID={facetState.facetUpdateID} + facets={facetState.facets} + layoutConfig={layoutConfig} /> ) break @@ -441,7 +371,11 @@ const ResultClassRoute = props => { routeComponent = <></> break } - return routeComponent + return ( + <Route path={path}> + {routeComponent} + </Route> + ) } export default ResultClassRoute diff --git a/src/client/components/facet_results/ResultTable.js b/src/client/components/facet_results/ResultTable.js index 5ba30fdf2a5ca2ba225dee0e07c16ad0edfaac4f..e4cf39b1e32571a16cad1712080d1180ca4e77ac 100644 --- a/src/client/components/facet_results/ResultTable.js +++ b/src/client/components/facet_results/ResultTable.js @@ -85,10 +85,10 @@ class ResultTable extends React.Component { let page // first check if page was given as url parameter - if (this.props.routeProps.location.search === '') { + if (this.props.location.search === '') { page = this.props.data.page === -1 ? 0 : this.props.data.page } else { - const qs = this.props.routeProps.location.search.replace('?', '') + const qs = this.props.location.search.replace('?', '') page = parseInt(querystring.parse(qs).page) } @@ -126,7 +126,7 @@ class ResultTable extends React.Component { // handle browser's back button window.onpopstate = () => { - const qs = this.props.routeProps.location.search.replace('?', '') + const qs = this.props.location.search.replace('?', '') const newPage = parseInt(querystring.parse(qs).page) if (newPage !== this.props.data.page) { this.props.updatePage(this.props.resultClass, newPage) @@ -338,7 +338,6 @@ class ResultTable extends React.Component { onSortBy={this.handleSortBy} sortBy={sortBy} sortDirection={sortDirection} - routeProps={this.props.routeProps} /> <TableBody> {paginatedResults.map(row => this.rowRenderer(row))} @@ -361,7 +360,7 @@ ResultTable.propTypes = { sortResults: PropTypes.func.isRequired, updatePage: PropTypes.func.isRequired, updateRowsPerPage: PropTypes.func.isRequired, - routeProps: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, rootUrl: PropTypes.string.isRequired } diff --git a/src/client/components/facet_results/ResultTable.stories.js b/src/client/components/facet_results/ResultTable.stories.js index 16acce75d89f770d1ec3e7cf0a6109c15e94ebfb..cb9a94766ab6ca2a42339d3e47ae52c8f0cf3690 100644 --- a/src/client/components/facet_results/ResultTable.stories.js +++ b/src/client/components/facet_results/ResultTable.stories.js @@ -11,9 +11,6 @@ export default { export const basic = () => { const facetResults = useSelector(state => state.perspective1) const location = useLocation() - const routeProps = { - location - } return ( <div style={{ width: '100%', height: '100%' }}> <ResultTable @@ -25,7 +22,7 @@ export const basic = () => { updatePage={() => null} updateRowsPerPage={() => null} sortResults={() => null} - routeProps={routeProps} + location={location} rootUrl='' /> </div> diff --git a/src/client/components/facet_results/ResultTableHead.js b/src/client/components/facet_results/ResultTableHead.js index 2d9f2a939d98a9045cc4d8172e6d1181b4b64aab..69bec665cbe84cf961a305dd96061596838d078d 100644 --- a/src/client/components/facet_results/ResultTableHead.js +++ b/src/client/components/facet_results/ResultTableHead.js @@ -98,8 +98,7 @@ ResultTableHead.propTypes = { columns: PropTypes.array.isRequired, onSortBy: PropTypes.func.isRequired, sortBy: PropTypes.string, - sortDirection: PropTypes.string, - routeProps: PropTypes.object.isRequired + sortDirection: PropTypes.string } export default withStyles(styles)(ResultTableHead) diff --git a/src/client/components/main_layout/FullTextSearch.js b/src/client/components/main_layout/FullTextSearch.js index 937b62bb7319866f84444a89a9e6a3efb479a4ea..c0a851e417de8caba2f0f34df5c54dc65dc27cf6 100644 --- a/src/client/components/main_layout/FullTextSearch.js +++ b/src/client/components/main_layout/FullTextSearch.js @@ -1,29 +1,35 @@ import React from 'react' import PropTypes from 'prop-types' import { Route, Redirect } from 'react-router-dom' -import makeStyles from '@mui/styles/makeStyles' +import Box from '@mui/material/Box' import PerspectiveTabs from './PerspectiveTabs' import ReactVirtualizedTable from '../facet_results/ReactVirtualizedTable' import CalendarViewDayIcon from '@mui/icons-material/CalendarViewDay' - -const useStyles = makeStyles(theme => ({ - root: props => ({ - marginTop: theme.spacing(0.5), - height: `calc(100% - ${props.layoutConfig.tabHeight - 18}px)` - }) -})) +import { getSpacing } from '../../helpers/helpers' /** * A component for displaying full text search results. */ const FullTextSearch = props => { const { rootUrl, layoutConfig, screenSize } = props - const classes = useStyles(props) const perspectiveUrl = `${rootUrl}/full-text-search` return ( - <div className={classes.root}> + <Box + sx={theme => ({ + margin: theme.spacing(0.5), + [theme.breakpoints.up(layoutConfig.hundredPercentHeightBreakPoint)]: { + height: `calc(100% - ${layoutConfig.topBar.reducedHeight + + getSpacing(theme, 1) + }px)` + }, + [theme.breakpoints.up(layoutConfig.reducedHeightBreakpoint)]: { + height: `calc(100% - ${layoutConfig.topBar.defaultHeight + + getSpacing(theme, 1) + }px)` + } + })} + > <PerspectiveTabs - routeProps={props.routeProps} tabs={[{ id: 'table', label: 'table', @@ -33,30 +39,23 @@ const FullTextSearch = props => { screenSize={screenSize} layoutConfig={layoutConfig} /> - <Route - exact path={perspectiveUrl} - render={() => <Redirect to={`${perspectiveUrl}/table`} />} - /> - <Route - path={`${perspectiveUrl}/table`} - render={() => { - return ( - <ReactVirtualizedTable - fullTextSearch={props.fullTextSearch} - resultClass={props.resultClass} - sortFullTextResults={props.sortFullTextResults} - layoutConfig={props.layoutConfig} - /> - ) - }} - /> - </div> + <Route exact path={perspectiveUrl}> + <Redirect to={`${perspectiveUrl}/table`} /> + </Route> + <Route path={`${perspectiveUrl}/table`}> + <ReactVirtualizedTable + fullTextSearch={props.fullTextSearch} + resultClass={props.resultClass} + sortFullTextResults={props.sortFullTextResults} + layoutConfig={props.layoutConfig} + /> + </Route> + </Box> ) } FullTextSearch.propTypes = { fullTextSearch: PropTypes.object.isRequired, - routeProps: PropTypes.object.isRequired, screenSize: PropTypes.string.isRequired, rootUrl: PropTypes.string.isRequired } diff --git a/src/client/components/main_layout/InstancePage.js b/src/client/components/main_layout/InstancePage.js index b7ff28ea6744ae4a11f49c624e0525f4ee16a066..1e84ee0f8dc9e49c5ccfa6e248e1c3f8ff59c853 100644 --- a/src/client/components/main_layout/InstancePage.js +++ b/src/client/components/main_layout/InstancePage.js @@ -45,8 +45,8 @@ class InstancePage extends React.Component { componentDidUpdate = prevProps => { // handle the case when the TABLE tab was not originally active - const prevPathname = prevProps.routeProps.location.pathname - const currentPathname = this.props.routeProps.location.pathname + const prevPathname = prevProps.location.pathname + const currentPathname = this.props.location.pathname if (!this.hasTableData() && prevPathname !== currentPathname && currentPathname.endsWith('table')) { this.fetchTableData() } @@ -59,7 +59,7 @@ class InstancePage extends React.Component { getLocalID = () => { return getLocalIDFromAppLocation({ - location: this.props.routeProps.location, + location: this.props.location, perspectiveConfig: this.props.perspectiveConfig }) } @@ -112,7 +112,6 @@ class InstancePage extends React.Component { return ( <div className={classes.root}> <PerspectiveTabs - routeProps={this.props.routeProps} tabs={perspectiveConfig.instancePageTabs} screenSize={screenSize} layoutConfig={layoutConfig} @@ -230,7 +229,7 @@ InstancePage.propTypes = { /** * Routing information from React Router. */ - routeProps: PropTypes.object.isRequired, + location: PropTypes.object.isRequired, /** * Perspective config. */ diff --git a/src/client/components/main_layout/InstancePagePerspective.js b/src/client/components/main_layout/InstancePagePerspective.js index 43691cdb3124e7316896870638acb4a179efddb0..3f91c1d9b3ecb4244f417788ed07af7187c1fa8a 100644 --- a/src/client/components/main_layout/InstancePagePerspective.js +++ b/src/client/components/main_layout/InstancePagePerspective.js @@ -3,12 +3,13 @@ import InfoHeader from '../main_layout/InfoHeader' import InstancePage from './InstancePage' import Grid from '@mui/material/Grid' import { getSpacing } from '../../helpers/helpers' +import { useLocation } from 'react-router-dom' const InstancePagePerspective = props => { const { portalConfig, layoutConfig, perspective, perspectiveState, screenSize, rootUrl, apexChartsConfig, networkConfig, - leafletConfig, routeProps + leafletConfig } = props const { instancePageHeaderExpanded } = perspectiveState return ( @@ -95,7 +96,6 @@ const InstancePagePerspective = props => { updateMapBounds={props.updateMapBounds} sortResults={props.sortResults} showError={props.showError} - routeProps={routeProps} perspective={perspective} animationValue={props.animationValue} animateMap={props.animateMap} @@ -106,6 +106,7 @@ const InstancePagePerspective = props => { apexChartsConfig={apexChartsConfig} leafletConfig={leafletConfig} networkConfig={networkConfig} + location={useLocation()} /> </Grid> </Grid> diff --git a/src/client/components/main_layout/PerspectiveTabs.js b/src/client/components/main_layout/PerspectiveTabs.js index 869078fc8ecc21d0787a29ede04f36b3ee8d9b9a..d5f7374e694991d3e052a67e7ea28a8324ebf677 100644 --- a/src/client/components/main_layout/PerspectiveTabs.js +++ b/src/client/components/main_layout/PerspectiveTabs.js @@ -1,104 +1,86 @@ -import React from 'react' +import React, { useState, useEffect } from 'react' import PropTypes from 'prop-types' +import { Link, useLocation } from 'react-router-dom' import Tabs from '@mui/material/Tabs' import Tab from '@mui/material/Tab' -import { Link } from 'react-router-dom' import Paper from '@mui/material/Paper' import intl from 'react-intl-universal' +// helper function for converting a tab path into tab index value +const pathnameToTabValue = (location, tabs) => { + const activeID = location.pathname.split('/').pop() + let value = 0 + tabs.forEach(tab => { + if (tab.id === activeID) { + value = tab.value + } + }) + return value +} + /** - * A component for generating view tabs for a faceted search perspective or an entity landing page. + * A component for generating view tabs for a faceted search perspective or an instance page. */ -class PerspectiveTabs extends React.Component { - constructor (props) { - super(props) - this.state = { - value: this.pathnameToValue(this.props.routeProps.location.pathname) - } - } +const PerspectiveTabs = props => { + const { tabs, layoutConfig } = props + const variant = tabs.length > 3 ? 'scrollable' : 'fullWidth' + // const largeScreen = screenSize === 'xl' + // const scrollButtons = tabs.length > 3 ? 'auto' : 'on' + const location = useLocation() - componentDidUpdate = prevProps => { - const newPath = this.props.routeProps.location.pathname - const oldPath = prevProps.routeProps.location.pathname - if (newPath !== oldPath) { - this.setState({ value: this.pathnameToValue(newPath) }) - } + const [value, setValue] = useState(pathnameToTabValue(location, tabs)) - // Fix tabs indicator not showing on first load, not needed any more? - // https://stackoverflow.com/a/61205108 - // const evt = document.createEvent('UIEvents') - // evt.initUIEvent('resize', true, false, window, 0) - // window.dispatchEvent(evt) - } + useEffect(() => { + setValue(pathnameToTabValue(location, tabs)) + }, [location]) - pathnameToValue = pathname => { - const activeID = pathname.split('/').pop() - let value = 0 - this.props.tabs.forEach(tab => { - if (tab.id === activeID) { - value = tab.value - } - }) - return value + const handleChange = (event, newValue) => { + setValue(newValue) } - handleChange = (event, value) => { - this.setState({ value }) - }; - - render () { - const { tabs } = this.props - const { value } = this.state - // const largeScreen = screenSize === 'xl' - const variant = tabs.length > 3 ? 'scrollable' : 'fullWidth' - // const scrollButtons = tabs.length > 3 ? 'auto' : 'on' - return ( - <Paper - sx={theme => ({ - flexGrow: 1, - borderBottomLeftRadius: 0, - borderBottomRightRadius: 0 - })} + return ( + <Paper + sx={theme => ({ + flexGrow: 1, + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0 + })} + > + <Tabs + value={value} + onChange={handleChange} + indicatorColor='secondary' + textColor='secondary' + variant={variant} > - <Tabs - value={value} - onChange={this.handleChange} - indicatorColor='secondary' - textColor='secondary' - variant={variant} - > - {tabs.map(tab => - <Tab - sx={theme => ({ - paddingTop: theme.spacing(0.5), - paddingBottom: theme.spacing(0.5), - minHeight: this.props.layoutConfig.tabHeight, - '& .MuiSvgIcon-root': { - marginBottom: theme.spacing(0.5) - } - })} - key={tab.value} - value={tab.value} - icon={tab.icon} - label={intl.get(`tabs.${tab.id}`)} - component={Link} - to={tab.id} - wrapped - /> - )} - </Tabs> - </Paper> - ) - } + {tabs.map(tab => + <Tab + sx={theme => ({ + paddingTop: theme.spacing(0.5), + paddingBottom: theme.spacing(0.5), + minHeight: layoutConfig.tabHeight, + '& .MuiSvgIcon-root': { + marginBottom: theme.spacing(0.5) + } + })} + key={tab.value} + value={tab.value} + icon={tab.icon} + label={intl.get(`tabs.${tab.id}`)} + component={Link} + to={tab.id} + wrapped + /> + )} + </Tabs> + </Paper> + ) } PerspectiveTabs.propTypes = { - routeProps: PropTypes.object.isRequired, tabs: PropTypes.array.isRequired, screenSize: PropTypes.string.isRequired, layoutConfig: PropTypes.object.isRequired } -export const PerspectiveTabsComponent = PerspectiveTabs - export default PerspectiveTabs diff --git a/src/client/components/main_layout/PerspectiveTabs.stories.js b/src/client/components/main_layout/PerspectiveTabs.stories.js index 619693ec9908a82d6a9f1a1ea8ed5feeb85ce1bf..9e3102bfd99d2eba3e8f7702f71fef522f711481 100644 --- a/src/client/components/main_layout/PerspectiveTabs.stories.js +++ b/src/client/components/main_layout/PerspectiveTabs.stories.js @@ -1,7 +1,6 @@ import React from 'react' import PerspectiveTabs, { PerspectiveTabsComponent } from './PerspectiveTabs' import { perspectiveConfig } from '../../configs/sampo/PerspectiveConfig' -import { useLocation } from 'react-router-dom' export default { component: PerspectiveTabsComponent, @@ -10,11 +9,8 @@ export default { export const basic = () => { const perspective = perspectiveConfig[0] - const location = useLocation() - const routeProps = { location } return ( <PerspectiveTabs - routeProps={routeProps} tabs={perspective.tabs} screenSize='md' /> diff --git a/src/client/components/main_layout/Player.js b/src/client/components/main_layout/Player.js index d01ec655fd5774d857247f043691d7738ba80560..e8b03c69f0b63fb86c0a77b258a24724aa6b9c7d 100644 --- a/src/client/components/main_layout/Player.js +++ b/src/client/components/main_layout/Player.js @@ -1,5 +1,5 @@ import React from 'react' -import withStyles from '@mui/styles/withStyles'; +import withStyles from '@mui/styles/withStyles' const styles = theme => ({ // https://www.w3schools.com/howto/howto_css_responsive_iframes.asp @@ -38,7 +38,7 @@ class Player extends React.Component { } componentDidUpdate = prevProps => { - if (this.props.routeProps.location.hash !== prevProps.routeProps.location.hash) { + if (this.props.location.hash !== prevProps.location.hash) { this.seekToBasedOnHash() } } @@ -50,7 +50,7 @@ class Player extends React.Component { } seekToBasedOnHash = () => { - const seconds = this.props.routeProps.location.hash.substring(1) + const seconds = this.props.location.hash.substring(1) // https://developers.google.com/youtube/iframe_api_reference#seekTo this.player.seekTo(seconds) } @@ -71,7 +71,7 @@ class Player extends React.Component { } onPlayerReady = event => { - if (this.props.routeProps.location.hash === '') { + if (this.props.location.hash === '') { this.props.updateVideoPlayerTime(parseInt(this.player.getCurrentTime())) } else { this.seekToBasedOnHash() diff --git a/src/client/components/main_layout/VideoPage.js b/src/client/components/main_layout/VideoPage.js index 19ae3796d8015bce32d115737d3c94105fcda757..c0d9a245af16117cdca5cbafcb6bf265ee9e8cb6 100644 --- a/src/client/components/main_layout/VideoPage.js +++ b/src/client/components/main_layout/VideoPage.js @@ -1,5 +1,5 @@ import React from 'react' -import makeStyles from '@mui/styles/makeStyles'; +import makeStyles from '@mui/styles/makeStyles' import Paper from '@mui/material/Paper' import Grid from '@mui/material/Grid' import { Typography } from '@mui/material' @@ -7,6 +7,7 @@ import InstancePageTable from './InstancePageTable' import Player from './Player' import VideoTableOfContents from './VideoTableOfContents' import { has } from 'lodash' +import { useLocation } from 'react-router-dom' const useStyles = makeStyles(theme => ({ root: { @@ -111,7 +112,7 @@ const VideoPage = props => { <Player resultClass={props.resultClass} data={instanceTableData} - routeProps={props.routeProps} + location={useLocation()} videoPlayerState={props.videoPlayerState} updateVideoPlayerTime={props.updateVideoPlayerTime} />} diff --git a/src/client/containers/SemanticPortal.js b/src/client/containers/SemanticPortal.js index b1cd4e287f850fb8d7982cb0efdf467397c9888e..f35202027a9076036a7d241c809c4612a03ad6bf 100644 --- a/src/client/containers/SemanticPortal.js +++ b/src/client/containers/SemanticPortal.js @@ -3,8 +3,7 @@ import PropTypes from 'prop-types' import intl from 'react-intl-universal' import { has } from 'lodash' import { connect } from 'react-redux' -import { withRouter, Route, Redirect, Switch } from 'react-router-dom' -import { compose } from '@shakacode/recompose' +import { Route, Redirect, Switch, useLocation } from 'react-router-dom' import Box from '@mui/material/Box' import { fetchResultCount, @@ -45,7 +44,8 @@ import { processPortalConfig, createPerspectiveConfig, createPerspectiveConfigOnlyInfoPages, - getScreenSize + getScreenSize, + usePageViews } from '../helpers/helpers' import * as apexChartsConfig from '../library_configs/ApexCharts/ApexChartsConfig' import * as leafletConfig from '../library_configs/Leaflet/LeafletConfig' @@ -94,10 +94,15 @@ const Footer = lazy(() => import(`../components/perspectives/${portalID}/Footer` */ const SemanticPortal = props => { const { error } = props + const location = useLocation() const rootUrlWithLang = `${rootUrl}/${props.options.currentLocale}` const screenSize = getScreenSize() const noClientFSResults = props.clientFSState && props.clientFSState.results === null + // trigger a new “page view†event whenever a new page loads + usePageViews() + + // set HTML title and description dynamically based on translations useEffect(() => { document.title = intl.get('html.title') document.documentElement.lang = props.options.currentLocale @@ -116,10 +121,10 @@ const SemanticPortal = props => { } })} > - {/* Error messages are shown on top of the app. */} + {/* error messages are shown on top of the app */} <Message error={error} /> <> - {/* No route for TopBar, because it is always visible. */} + {/* no route for TopBar, because it is always visible */} <TopBar rootUrl={rootUrlWithLang} search={props.fullTextSearch} @@ -131,278 +136,247 @@ const SemanticPortal = props => { availableLocales={props.options.availableLocales} loadLocales={props.loadLocales} screenSize={screenSize} - location={props.location} + location={location} layoutConfig={layoutConfig} /> - {/* Enforce a lang tag. */} + {/* enforce a lang tag */} <Route exact path={`${rootUrl}/`}> <Redirect to={rootUrlWithLang} /> </Route> - {/* Create a route for portal front page. */} - <Route - exact path={`${rootUrlWithLang}/`} - render={() => - <> - <Main - perspectives={perspectiveConfig} - screenSize={screenSize} - rootUrl={rootUrlWithLang} - layoutConfig={layoutConfig} - /> - <Footer - portalConfig={portalConfig} - layoutConfig={layoutConfig} - /> - </>} - /> - {/* https://stackoverflow.com/a/41024944 */} - <Route - path={`${rootUrlWithLang}/`} render={({ location }) => { - if (typeof window.ga === 'function') { - window.ga('set', 'page', location.pathname + location.search) - window.ga('send', 'pageview') - } - return null - }} - /> - {/* Create a route for full text search results. */} - <Route - path={`${rootUrlWithLang}/full-text-search`} - render={routeProps => - <FullTextSearch - fullTextSearch={props.fullTextSearch} - resultClass='fullTextSearch' - sortFullTextResults={props.sortFullTextResults} - routeProps={routeProps} + {/* create a route for portal front page */} + <Route exact path={`${rootUrlWithLang}`}> + <> + <Main + perspectives={perspectiveConfig} screenSize={screenSize} rootUrl={rootUrlWithLang} layoutConfig={layoutConfig} - />} - /> - {/* Create routes for faceted search perspectives and corresponding instance pages. */} + /> + <Footer + portalConfig={portalConfig} + layoutConfig={layoutConfig} + /> + </> + </Route> + {/* create a route for full text search results */} + <Route path={`${rootUrlWithLang}/full-text-search`}> + <FullTextSearch + fullTextSearch={props.fullTextSearch} + resultClass='fullTextSearch' + sortFullTextResults={props.sortFullTextResults} + screenSize={screenSize} + rootUrl={rootUrlWithLang} + layoutConfig={layoutConfig} + /> + </Route> + {/* create routes for faceted search perspectives and corresponding instance pages */} {perspectiveConfig.map(perspective => { if (!has(perspective, 'externalUrl') && perspective.searchMode === 'faceted-search') { return ( <React.Fragment key={perspective.id}> - <Route - path={`${rootUrlWithLang}/${perspective.id}/faceted-search`} - render={routeProps => - <FacetedSearchPerspective + <Route path={`${rootUrlWithLang}/${perspective.id}/faceted-search`}> + <FacetedSearchPerspective + portalConfig={portalConfig} + perspectiveConfig={perspective} + layoutConfig={layoutConfig} + facetedSearchMode='serverFS' + facetState={props[`${perspective.id}Facets`]} + facetStateConstrainSelf={props[`${perspective.id}FacetsConstrainSelf`]} + perspectiveState={props[perspective.id]} + facetClass={perspective.id} + resultClass={perspective.id} + fetchingResultCount={props[perspective.id].fetchingResultCount} + resultCount={props[perspective.id].resultCount} + fetchFacet={props.fetchFacet} + fetchFacetConstrainSelf={props.fetchFacetConstrainSelf} + fetchResults={props.fetchResults} + clearFacet={props.clearFacet} + clearAllFacets={props.clearAllFacets} + fetchResultCount={props.fetchResultCount} + updateFacetOption={props.updateFacetOption} + showError={props.showError} + defaultActiveFacets={perspective.defaultActiveFacets} + rootUrl={rootUrlWithLang} + screenSize={screenSize} + apexChartsConfig={apexChartsConfig} + leafletConfig={leafletConfig} + networkConfig={networkConfig} + leafletMapState={props.leafletMap} + fetchPaginatedResults={props.fetchPaginatedResults} + fetchInstanceAnalysis={props.fetchInstanceAnalysis} + fetchGeoJSONLayers={props.fetchGeoJSONLayers} + fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} + clearGeoJSONLayers={props.clearGeoJSONLayers} + fetchByURI={props.fetchByURI} + updatePage={props.updatePage} + updateRowsPerPage={props.updateRowsPerPage} + updateMapBounds={props.updateMapBounds} + updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded} + sortResults={props.sortResults} + perspective={perspective} + animationValue={props.animationValue} + animateMap={props.animateMap} + /> + </Route> + <Switch> + <Redirect + from={`/${perspective.id}/page/:id`} + to={{ + pathname: `${rootUrlWithLang}/${perspective.id}/page/:id`, + hash: location.hash + }} + /> + <Route path={`${rootUrlWithLang}/${perspective.id}/page/:id`}> + <InstancePagePerspective portalConfig={portalConfig} - perspectiveConfig={perspective} layoutConfig={layoutConfig} - facetedSearchMode='serverFS' - facetState={props[`${perspective.id}Facets`]} - facetStateConstrainSelf={props[`${perspective.id}FacetsConstrainSelf`]} - perspectiveState={props[perspective.id]} - facetClass={perspective.id} - resultClass={perspective.id} - fetchingResultCount={props[perspective.id].fetchingResultCount} - resultCount={props[perspective.id].resultCount} - fetchFacet={props.fetchFacet} - fetchFacetConstrainSelf={props.fetchFacetConstrainSelf} - fetchResults={props.fetchResults} - clearFacet={props.clearFacet} - clearAllFacets={props.clearAllFacets} - fetchResultCount={props.fetchResultCount} - updateFacetOption={props.updateFacetOption} - showError={props.showError} - defaultActiveFacets={perspective.defaultActiveFacets} - rootUrl={rootUrlWithLang} - screenSize={screenSize} - apexChartsConfig={apexChartsConfig} - leafletConfig={leafletConfig} - networkConfig={networkConfig} + perspectiveConfig={perspective} + perspectiveState={props[`${perspective.id}`]} leafletMapState={props.leafletMap} fetchPaginatedResults={props.fetchPaginatedResults} + fetchResults={props.fetchResults} fetchInstanceAnalysis={props.fetchInstanceAnalysis} + fetchFacetConstrainSelf={props.fetchFacetConstrainSelf} fetchGeoJSONLayers={props.fetchGeoJSONLayers} fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} clearGeoJSONLayers={props.clearGeoJSONLayers} fetchByURI={props.fetchByURI} updatePage={props.updatePage} updateRowsPerPage={props.updateRowsPerPage} + updateFacetOption={props.updateFacetOption} updateMapBounds={props.updateMapBounds} - updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded} sortResults={props.sortResults} - routeProps={routeProps} + showError={props.showError} perspective={perspective} animationValue={props.animationValue} animateMap={props.animateMap} - />} - /> - <Switch> - <Redirect - from={`/${perspective.id}/page/:id`} - to={{ - pathname: `${rootUrlWithLang}/${perspective.id}/page/:id`, - hash: props.location.hash - }} - /> - <Route - path={`${rootUrlWithLang}/${perspective.id}/page/:id`} - render={routeProps => - <InstancePagePerspective - portalConfig={portalConfig} - layoutConfig={layoutConfig} - perspectiveConfig={perspective} - perspectiveState={props[`${perspective.id}`]} - leafletMapState={props.leafletMap} - fetchPaginatedResults={props.fetchPaginatedResults} - fetchResults={props.fetchResults} - fetchInstanceAnalysis={props.fetchInstanceAnalysis} - fetchFacetConstrainSelf={props.fetchFacetConstrainSelf} - fetchGeoJSONLayers={props.fetchGeoJSONLayers} - fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} - clearGeoJSONLayers={props.clearGeoJSONLayers} - fetchByURI={props.fetchByURI} - updatePage={props.updatePage} - updateRowsPerPage={props.updateRowsPerPage} - updateFacetOption={props.updateFacetOption} - updateMapBounds={props.updateMapBounds} - sortResults={props.sortResults} - showError={props.showError} - routeProps={routeProps} - perspective={perspective} - animationValue={props.animationValue} - animateMap={props.animateMap} - videoPlayerState={props.videoPlayer} - updateVideoPlayerTime={props.updateVideoPlayerTime} - updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded} - screenSize={screenSize} - rootUrl={rootUrlWithLang} - apexChartsConfig={apexChartsConfig} - leafletConfig={leafletConfig} - networkConfig={networkConfig} - />} - /> + videoPlayerState={props.videoPlayer} + updateVideoPlayerTime={props.updateVideoPlayerTime} + updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded} + screenSize={screenSize} + rootUrl={rootUrlWithLang} + apexChartsConfig={apexChartsConfig} + leafletConfig={leafletConfig} + networkConfig={networkConfig} + /> + </Route> </Switch> </React.Fragment> ) } return null })} - {/* Create routes for perspectives that have only instance pages. */} + {/* create routes for perspectives that have only instance pages */} {perspectiveConfigOnlyInfoPages.map(perspective => <Switch key={perspective.id}> <Redirect from={`${rootUrl}/${perspective.id}/page/:id`} to={`${rootUrlWithLang}/${perspective.id}/page/:id`} /> - <Route - path={`${rootUrlWithLang}/${perspective.id}/page/:id`} - render={routeProps => - <InstancePagePerspective - portalConfig={portalConfig} - layoutConfig={layoutConfig} - perspectiveConfig={perspective} - perspectiveState={props[`${perspective.id}`]} - leafletMapState={props.leafletMap} - fetchPaginatedResults={props.fetchPaginatedResults} - fetchResults={props.fetchResults} - fetchInstanceAnalysis={props.fetchInstanceAnalysis} - fetchFacetConstrainSelf={props.fetchFacetConstrainSelf} - fetchGeoJSONLayers={props.fetchGeoJSONLayers} - fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} - clearGeoJSONLayers={props.clearGeoJSONLayers} - fetchByURI={props.fetchByURI} - updatePage={props.updatePage} - updateRowsPerPage={props.updateRowsPerPage} - updateFacetOption={props.updateFacetOption} - updateMapBounds={props.updateMapBounds} - sortResults={props.sortResults} - showError={props.showError} - routeProps={routeProps} - perspective={perspective} - animationValue={props.animationValue} - animateMap={props.animateMap} - videoPlayerState={props.videoPlayer} - updateVideoPlayerTime={props.updateVideoPlayerTime} - updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded} - screenSize={screenSize} - rootUrl={rootUrlWithLang} - apexChartsConfig={apexChartsConfig} - leafletConfig={leafletConfig} - networkConfig={networkConfig} - />} - /> + <Route path={`${rootUrlWithLang}/${perspective.id}/page/:id`}> + <InstancePagePerspective + portalConfig={portalConfig} + layoutConfig={layoutConfig} + perspectiveConfig={perspective} + perspectiveState={props[`${perspective.id}`]} + leafletMapState={props.leafletMap} + fetchPaginatedResults={props.fetchPaginatedResults} + fetchResults={props.fetchResults} + fetchInstanceAnalysis={props.fetchInstanceAnalysis} + fetchFacetConstrainSelf={props.fetchFacetConstrainSelf} + fetchGeoJSONLayers={props.fetchGeoJSONLayers} + fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} + clearGeoJSONLayers={props.clearGeoJSONLayers} + fetchByURI={props.fetchByURI} + updatePage={props.updatePage} + updateRowsPerPage={props.updateRowsPerPage} + updateFacetOption={props.updateFacetOption} + updateMapBounds={props.updateMapBounds} + sortResults={props.sortResults} + showError={props.showError} + perspective={perspective} + animationValue={props.animationValue} + animateMap={props.animateMap} + videoPlayerState={props.videoPlayer} + updateVideoPlayerTime={props.updateVideoPlayerTime} + updatePerspectiveHeaderExpanded={props.updatePerspectiveHeaderExpanded} + screenSize={screenSize} + rootUrl={rootUrlWithLang} + apexChartsConfig={apexChartsConfig} + leafletConfig={leafletConfig} + networkConfig={networkConfig} + /> + </Route> </Switch> )} - {/* Optional: create a route for client side faceted search. */} - <Route - path={`${rootUrlWithLang}/perspective4/federated-search`} - render={routeProps => - <FederatedSearchPerspective - portalConfig={portalConfig} - layoutConfig={layoutConfig} - facetedSearchMode='clientFS' - facetClass='perspective4' - resultClass='perspective4' - facetState={props.clientFSState} - clientFSFacetValues={props.clientFSFacetValues} - fetchingResultCount={props.clientFSState.textResultsFetching} - resultCount={noClientFSResults ? 0 : props.clientFSState.results.length} - noClientFSResults={noClientFSResults} - clientFSState={props.clientFSState} - clientFSToggleDataset={props.clientFSToggleDataset} - clientFSFetchResults={props.clientFSFetchResults} - clientFSClearResults={props.clientFSClearResults} - clientFSUpdateQuery={props.clientFSUpdateQuery} - clientFSUpdateFacet={props.clientFSUpdateFacet} - defaultActiveFacets={perspectiveConfig.find(p => p.id === 'perspective4').defaultActiveFacets} - updateMapBounds={props.updateMapBounds} - screenSize={screenSize} - showError={props.showError} - rootUrl={rootUrlWithLang} - apexChartsConfig={apexChartsConfig} - leafletConfig={leafletConfig} - networkConfig={networkConfig} - perspective={perspectiveConfig.find(p => p.id === 'perspective4')} - routeProps={routeProps} - clientFSResults={props.clientFSResults} - clientFSSortResults={props.clientFSSortResults} - leafletMapState={props.leafletMap} - fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} - fetchGeoJSONLayers={props.fetchGeoJSONLayers} - clearGeoJSONLayers={props.clearGeoJSONLayers} - />} - /> - {/* Create routes for top bar info buttons. */} + {/* optional: create a route for client side faceted search */} + <Route path={`${rootUrlWithLang}/perspective4/federated-search`}> + <FederatedSearchPerspective + portalConfig={portalConfig} + layoutConfig={layoutConfig} + facetedSearchMode='clientFS' + facetClass='perspective4' + resultClass='perspective4' + facetState={props.clientFSState} + clientFSFacetValues={props.clientFSFacetValues} + fetchingResultCount={props.clientFSState.textResultsFetching} + resultCount={noClientFSResults ? 0 : props.clientFSState.results.length} + noClientFSResults={noClientFSResults} + clientFSState={props.clientFSState} + clientFSToggleDataset={props.clientFSToggleDataset} + clientFSFetchResults={props.clientFSFetchResults} + clientFSClearResults={props.clientFSClearResults} + clientFSUpdateQuery={props.clientFSUpdateQuery} + clientFSUpdateFacet={props.clientFSUpdateFacet} + defaultActiveFacets={perspectiveConfig.find(p => p.id === 'perspective4').defaultActiveFacets} + updateMapBounds={props.updateMapBounds} + screenSize={screenSize} + showError={props.showError} + rootUrl={rootUrlWithLang} + apexChartsConfig={apexChartsConfig} + leafletConfig={leafletConfig} + networkConfig={networkConfig} + perspective={perspectiveConfig.find(p => p.id === 'perspective4')} + clientFSResults={props.clientFSResults} + clientFSSortResults={props.clientFSSortResults} + leafletMapState={props.leafletMap} + fetchGeoJSONLayersBackend={props.fetchGeoJSONLayersBackend} + fetchGeoJSONLayers={props.fetchGeoJSONLayers} + clearGeoJSONLayers={props.clearGeoJSONLayers} + /> + </Route> + {/* create routes for top bar info buttons */} {!layoutConfig.topBar.externalAboutPage && - <Route - path={`${rootUrlWithLang}/about`} - render={() => - <TextPage layoutConfig={layoutConfig}> - {intl.getHTML('aboutThePortalPartOne')} - {knowledgeGraphMetadataConfig.showTable && - <KnowledgeGraphMetadataTable - portalConfig={portalConfig} - layoutConfig={layoutConfig} - perspectiveID={knowledgeGraphMetadataConfig.perspective} - resultClass='knowledgeGraphMetadata' - fetchKnowledgeGraphMetadata={props.fetchKnowledgeGraphMetadata} - knowledgeGraphMetadata={props[knowledgeGraphMetadataConfig.perspective] - ? props[knowledgeGraphMetadataConfig.perspective].knowledgeGraphMetadata - : null} - />} - {intl.getHTML('aboutThePortalPartTwo')} - </TextPage>} - />} - {/* Create a route for instructions page */} + <Route path={`${rootUrlWithLang}/about`}> + <TextPage layoutConfig={layoutConfig}> + {intl.getHTML('aboutThePortalPartOne')} + {knowledgeGraphMetadataConfig.showTable && + <KnowledgeGraphMetadataTable + portalConfig={portalConfig} + layoutConfig={layoutConfig} + perspectiveID={knowledgeGraphMetadataConfig.perspective} + resultClass='knowledgeGraphMetadata' + fetchKnowledgeGraphMetadata={props.fetchKnowledgeGraphMetadata} + knowledgeGraphMetadata={props[knowledgeGraphMetadataConfig.perspective] + ? props[knowledgeGraphMetadataConfig.perspective].knowledgeGraphMetadata + : null} + />} + {intl.getHTML('aboutThePortalPartTwo')} + </TextPage> + </Route>} + {/* create a route for instructions page */} {!layoutConfig.topBar.externalInstructions && - <Route - path={`${rootUrlWithLang}/instructions`} - render={() => - <TextPage layoutConfig={layoutConfig}> - {intl.getHTML('instructions')} - </TextPage>} - />} + <Route path={`${rootUrlWithLang}/instructions`}> + <TextPage layoutConfig={layoutConfig}> + {intl.getHTML('instructions')} + </TextPage> + </Route>} </> </Box> ) } -// State: connect the Redux store and React components. +// state: connect the Redux store and React components const mapStateToProps = state => { const stateToProps = {} perspectiveConfig.forEach(perspective => { @@ -434,7 +408,7 @@ const mapStateToProps = state => { return stateToProps } -// Actions: connect the Redux store and React components. +// actions: connect the Redux store and React components const mapDispatchToProps = ({ fetchResultCount, fetchPaginatedResults, @@ -598,10 +572,7 @@ SemanticPortal.propTypes = { clientFSUpdateFacet: PropTypes.func } -export default compose( - withRouter, - connect( - mapStateToProps, - mapDispatchToProps - ) +export default connect( + mapStateToProps, + mapDispatchToProps )(SemanticPortal) diff --git a/src/client/helpers/helpers.js b/src/client/helpers/helpers.js index 89d734dfc9d43fd4afa697189cb87ce69dcc455c..1f615609392f86619400dcefc3947816019475d4 100644 --- a/src/client/helpers/helpers.js +++ b/src/client/helpers/helpers.js @@ -1,4 +1,5 @@ -import React from 'react' +import React, { useEffect } from 'react' +import { useLocation } from 'react-router-dom' import querystring from 'querystring' import { has, sortBy } from 'lodash' import intl from 'react-intl-universal' @@ -307,3 +308,14 @@ export const getScreenSize = () => { if (xlScreen) { screenSize = 'xl' } return screenSize } + +// https://v5.reactrouter.com/web/api/Hooks/uselocation +export const usePageViews = () => { + const location = useLocation() + useEffect(() => { + if (typeof window.ga === 'function') { + console.log(window.ga) + window.ga.send(['pageview', location.pathname]) + } + }, [location]) +}