Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/user-event": "13.5.0",
"@types/leaflet.markercluster": "^1.5.6",
"@types/node": "22.18.10",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
Expand All @@ -38,13 +39,16 @@
"i18next": "25.6.0",
"i18next-http-backend": "3.0.2",
"js-md5": "0.8.3",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"moment-timezone": "0.5.43",
"react-bootstrap": "2.7.2",
"react-bootstrap-icons": "1.11.4",
"react-confetti": "6.1.0",
"react-hook-form": "7.51.2",
"react-i18next": "16.2.0",
"react-infinite-scroll-hook": "4.1.1",
"react-leaflet": "^4.2.1",
"react-loader-spinner": "5.3.4",
"react-markdown": "8.0.7",
"react-oauth2-code-pkce": "1.22.2",
Expand Down Expand Up @@ -131,6 +135,7 @@
"@storybook/test-runner": "0.23.0",
"@testing-library/cypress": "10.1.0",
"@types/chai-as-promised": "7.1.5",
"@types/leaflet": "^1.9.21",
"@types/node-sass": "4.11.3",
"@types/sinon": "10.0.13",
"@typescript-eslint/eslint-plugin": "5.51.0",
Expand Down
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { initAppConfig, requireAppConfig } from './config'
import { ConfigError } from './ConfigError'
import { ApiConfig } from '@iqss/dataverse-client-javascript'
import { DataverseApiAuthMechanism } from '@iqss/dataverse-client-javascript/dist/core/infra/repositories/ApiConfig'
import 'leaflet/dist/leaflet.css'

const AppEntrypoint = lazy(() => import('./index.app'))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
@import 'node_modules/@iqss/dataverse-design-system/src/lib/assets/styles/design-tokens/colors.module';
@import 'src/assets/mixins';

.view-tabs {
display: flex;
gap: 0;
border-bottom: 2px solid #dee2e6;
}

.tab,
.tab-active {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.4rem 0.9rem;
border: 1px solid #dee2e6;
border-bottom: none;
border-radius: 4px 4px 0 0;
background: none;
cursor: pointer;
font-size: 14px;
color: #0d6efd;
margin-bottom: -2px;
}

.tab-active {
color: #000;
background: #fff;
border-color: #dee2e6 #dee2e6 #fff;
font-weight: 500;
}

.hidden {
display: none;
}

.items-panel {
display: flex;
flex-direction: column;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { Stack } from '@iqss/dataverse-design-system'
import { useTranslation } from 'react-i18next'
import { CollectionMap } from '../collection-map/CollectionMap'
import { CollectionItemsPaginationInfo } from '@/collection/domain/models/CollectionItemsPaginationInfo'
import {
CollectionSearchCriteria,
Expand All @@ -27,6 +28,8 @@ import { ItemTypeChange } from '@/sections/collection/collection-items-panel/fil
import { SelectedFacets } from '@/sections/collection/collection-items-panel/selected-facets/SelectedFacets'
import { RouteWithParams } from '@/sections/Route.enum'
import { useCollectionRepositories } from '@/shared/contexts/repositories/RepositoriesProvider'
import listIcon from './assets/list.svg'
import mapIcon from './assets/map.svg'
import styles from './CollectionItemsPanel.module.scss'

interface CollectionItemsPanelProps {
Expand Down Expand Up @@ -60,6 +63,18 @@ export const CollectionItemsPanel = ({
const { setIsLoading } = useLoading()
const [_, setSearchParams] = useSearchParams()
const { t } = useTranslation('collection')
const [activeView, setActiveView] = useState<'list' | 'map'>(
() => (sessionStorage.getItem('collectionActiveTab') as 'list' | 'map' | null) ?? 'list'
)
const [mapInitialized, setMapInitialized] = useState(
() => sessionStorage.getItem('collectionActiveTab') === 'map'
)

const handleTabChange = (view: 'list' | 'map') => {
if (view === 'map') setMapInitialized(true)
sessionStorage.setItem('collectionActiveTab', view)
setActiveView(view)
}
useLoadMoreOnPopStateEvent(loadItemsOnBackAndForwardNavigation)

// This object will update every time we update a query param in the URL with the setSearchParams setter
Expand Down Expand Up @@ -378,31 +393,56 @@ export const CollectionItemsPanel = ({
isLoadingCollectionItems={isLoadingItems}
/>
)}

<ItemsList
parentCollectionAlias={collectionId}
items={accumulatedItems}
itemsListType={ItemsListType.COLLECTION_LIST}
error={error}
accumulatedCount={accumulatedCount}
isLoadingItems={isLoadingItems}
areItemsAvailable={areItemsAvailable}
hasNextPage={hasNextPage}
isEmptyItems={isEmptyItems}
hasSearchValue={currentSearchCriteria.hasSearchText()}
itemsTypesSelected={currentSearchCriteria.itemTypes as CollectionItemType[]}
hasFilterQueries={
currentSearchCriteria.filterQueries
? currentSearchCriteria.filterQueries.length > 0
: false
}
sortSelected={currentSearchCriteria.sort}
orderSelected={currentSearchCriteria.order}
paginationInfo={paginationInfo}
onBottomReach={handleLoadMoreOnBottomReach}
onSortChange={handleSortChange}
ref={itemsListContainerRef}
/>
<div className={styles['view-tabs']}>
<button
className={activeView === 'list' ? styles['tab-active'] : styles.tab}
onClick={() => handleTabChange('list')}>
<img src={listIcon} alt="" aria-hidden="true" /> List
</button>
<button
className={activeView === 'map' ? styles['tab-active'] : styles.tab}
onClick={() => handleTabChange('map')}>
<img src={mapIcon} alt="" aria-hidden="true" /> Map
</button>
</div>
{activeView === 'list' && (
<ItemsList
parentCollectionAlias={collectionId}
items={accumulatedItems}
itemsListType={ItemsListType.COLLECTION_LIST}
error={error}
accumulatedCount={accumulatedCount}
isLoadingItems={isLoadingItems}
areItemsAvailable={areItemsAvailable}
hasNextPage={hasNextPage}
isEmptyItems={isEmptyItems}
hasSearchValue={currentSearchCriteria.hasSearchText()}
itemsTypesSelected={currentSearchCriteria.itemTypes as CollectionItemType[]}
hasFilterQueries={
currentSearchCriteria.filterQueries
? currentSearchCriteria.filterQueries.length > 0
: false
}
sortSelected={currentSearchCriteria.sort}
orderSelected={currentSearchCriteria.order}
paginationInfo={paginationInfo}
onBottomReach={handleLoadMoreOnBottomReach}
onSortChange={handleSortChange}
ref={itemsListContainerRef}
/>
)}
{/* To prevent problems when leaflet renders a 0px map, the initial render is delayed until the map becomes visible. */}
{mapInitialized && (
// To prevent re-initializations, the map is hidden via CSS when its tab is closed.
<div className={activeView === 'map' ? undefined : styles.hidden}>
<CollectionMap
collectionId={collectionId}
searchText={currentSearchCriteria.searchText}
filterQueries={currentSearchCriteria.filterQueries}
isVisible={activeView === 'map'}
/>
</div>
)}
</Stack>
</div>
</section>
Expand Down
32 changes: 32 additions & 0 deletions src/sections/collection/collection-map/CollectionMap.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@import 'node_modules/@iqss/dataverse-design-system/src/lib/assets/styles/design-tokens/typography.module';

.map-wrapper {
border: 1px solid #dee2e6;
border-radius: 4px;
overflow: hidden;
background: #f5f5f5;
}

.map-status {
padding: 0.5rem 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid #dee2e6;
background: #fff;
}

.map-container {
height: 480px;
}

.results {
margin-right: 4px;
font-weight: $dv-font-weight-bold;
}

.error {
padding: 0.75rem;
color: #dc3545;
font-size: 14px;
}
Loading