Skip to content

Commit dadca61

Browse files
authored
Merge pull request #324 from performant-software/feature/cdp322_models
CDP #33 - Core data models
2 parents 4cac214 + 7837317 commit dadca61

File tree

16 files changed

+288
-111
lines changed

16 files changed

+288
-111
lines changed

packages/core-data/src/components/FacetTimeline.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,33 @@ type Props = {
5656
onLoad?: (events: Array<EventType>) => void,
5757

5858
/**
59-
* Typesense `useRange` hook.
59+
* The absolute min/max values for the timeline range.
6060
*/
61-
useRange: ({ attribute: string }) => ({ refine: (range: [number, number]) => void }) => void,
61+
range: {
62+
max: number,
63+
min: number
64+
},
65+
66+
/**
67+
* Callback fired when the slider value(s) are changed.
68+
*
69+
* @param any
70+
*/
71+
refine: (number | [number, number]) => void,
72+
73+
/**
74+
* The current value of the slider.
75+
*/
76+
start: [number, number],
6277

6378
/**
6479
* Zoom level increment.
6580
*/
6681
zoom?: number
6782
};
6883

69-
const FACET_EVENT_RANGE = 'event_range_facet';
70-
7184
const FacetTimeline = (props: Props) => {
72-
const { range = {}, refine, start = [] } = props.useRange({ attribute: FACET_EVENT_RANGE });
85+
const { range = {}, refine, start = [] } = props;
7386

7487
const from = Math.max(range.min, Number.isFinite(start[0]) ? start[0] : range.min);
7588
const to = Math.min(range.max, Number.isFinite(start[1]) ? start[1] : range.max);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import { Image } from 'lucide-react';
5+
6+
type Props = {
7+
alt?: string,
8+
src: string
9+
};
10+
11+
const HeaderImage = (props: Props) => (
12+
<div
13+
className='relative w-full h-[200px] flex-grow-0 flex-shrink-0 bg-muted/20 z-0'
14+
>
15+
<div
16+
className='absolute top-0 left-0 w-full h-full flex justify-center items-center'
17+
>
18+
<Image
19+
className='h-20 w-20 text-gray-400'
20+
strokeWidth={1}
21+
/>
22+
</div>
23+
<div
24+
className='absolute top-0 left-0 w-full h-full flex justify-center items-center'
25+
>
26+
<img
27+
alt={props.alt}
28+
className='object-cover h-full w-full'
29+
src={props.src}
30+
/>
31+
</div>
32+
</div>
33+
);
34+
35+
export default HeaderImage;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import _ from 'underscore';
5+
6+
type Item = {
7+
label: string,
8+
value: string
9+
};
10+
11+
type Props = {
12+
items: Array<Item>
13+
};
14+
15+
const KeyValueList = (props: Props) => (
16+
<ol
17+
className='text-sm mt-4 leading-6 overflow-hidden'
18+
>
19+
{ _.map(props.items, ({ label, value }) => (
20+
<li
21+
key={label}
22+
className='mb-2'
23+
>
24+
<div
25+
className='text-muted'
26+
>
27+
{ label }
28+
</div>
29+
<div
30+
className='font-medium overflow-hidden text-ellipsis'
31+
>
32+
{ value }
33+
</div>
34+
</li>
35+
))}
36+
</ol>
37+
);
38+
39+
export default KeyValueList;

packages/core-data/src/components/PlaceDetails.js

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// @flow
22

3-
import { Image } from 'lucide-react';
43
import React, { useCallback, useEffect, useMemo } from 'react';
54
import _ from 'underscore';
5+
import HeaderImage from './HeaderImage';
6+
import KeyValueList from './KeyValueList';
67
import { useLoader, usePlacesService } from '../hooks/CoreData';
78

89
type Props = {
@@ -20,7 +21,10 @@ type Props = {
2021
};
2122

2223
/**
23-
* This component renders a detail view for the passed Core Data place record.
24+
* This component renders a detail view for the passed Core Data place record. This component is deprecated, as it is
25+
* just a composition of other components, and will be removed in a future release.
26+
*
27+
* @deprecated
2428
*/
2529
const PlaceDetails = (props: Props) => {
2630
const PlacesService = usePlacesService();
@@ -71,27 +75,10 @@ const PlaceDetails = (props: Props) => {
7175
return (
7276
<>
7377
{ image && (
74-
<div
75-
className='relative w-full h-[200px] flex-grow-0 flex-shrink-0 bg-muted/20 z-0'
76-
>
77-
<div
78-
className='absolute top-0 left-0 w-full h-full flex justify-center items-center'
79-
>
80-
<Image
81-
className='h-20 w-20 text-gray-400'
82-
strokeWidth={1}
83-
/>
84-
</div>
85-
<div
86-
className='absolute top-0 left-0 w-full h-full flex justify-center items-center'
87-
>
88-
<img
89-
className='object-cover h-full w-full'
90-
src={image.content_iiif_url}
91-
alt={image.name}
92-
/>
93-
</div>
94-
</div>
78+
<HeaderImage
79+
alt={image.name}
80+
src={image.content_iiif_url}
81+
/>
9582
)}
9683
{ place && (
9784
<div
@@ -102,27 +89,11 @@ const PlaceDetails = (props: Props) => {
10289
>
10390
{ place.name }
10491
</h1>
105-
<ol
106-
className='text-sm mt-4 leading-6 overflow-hidden'
107-
>
108-
{ _.map(userDefined, ({ label, value }) => (
109-
<li
110-
key={label}
111-
className='mb-2'
112-
>
113-
<div
114-
className='text-muted'
115-
>
116-
{ label }
117-
</div>
118-
<div
119-
className='font-medium overflow-hidden text-ellipsis'
120-
>
121-
{ value }
122-
</div>
123-
</li>
124-
))}
125-
</ol>
92+
{ userDefined && (
93+
<KeyValueList
94+
items={userDefined}
95+
/>
96+
)}
12697
</div>
12798
)}
12899
</>

packages/core-data/src/components/SearchResultsLayer.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ type Props = {
2929
fitBoundingBox?: boolean,
3030

3131
/**
32-
* If `true`, polygons will be shown (when available) on the map
33-
* instead of points.
32+
* Path to the geometry attribute for each result.
3433
*/
35-
showPolygons?: boolean
34+
geometry: string,
3635
}
3736

3837
/**
@@ -50,10 +49,9 @@ const SearchResultsLayer = (props: Props) => {
5049
*
5150
* @type {unknown}
5251
*/
53-
const data = useMemo(
54-
() => !_.isEmpty(hits) && TypesenseUtils.toFeatureCollection(hits, props.showPolygons),
55-
[hits, props.showPolygons]
56-
);
52+
const data = useMemo(() => (
53+
!_.isEmpty(hits) && TypesenseUtils.toFeatureCollection(hits, props.geometry)
54+
), [hits, props.geometry]);
5755

5856
/**
5957
* Here we'll implement our own fitting of the bounding box once the search has completed and the map has loaded,

packages/core-data/src/hooks/CoreData.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import CoreDataContext from '../context/CoreData';
1111
import EventsService from '../services/Events';
1212
import InstancesService from '../services/Instances';
1313
import ItemsService from '../services/Items';
14+
import OrganizationsService from '../services/Organizations';
1415
import PeopleService from '../services/People';
1516
import PlacesService from '../services/Places';
1617
import WorksService from '../services/Works';
@@ -132,6 +133,16 @@ export const useItemsService = () => {
132133
return new ItemsService(baseUrl, projectIds);
133134
};
134135

136+
/**
137+
* Hook to initialize the organizations service.
138+
*
139+
* @returns {Items}
140+
*/
141+
export const useOrganizationsService = () => {
142+
const { baseUrl, projectIds } = useContext(CoreDataContext);
143+
return new OrganizationsService(baseUrl, projectIds);
144+
};
145+
135146
/**
136147
* Hook to initialize the people service.
137148
*

packages/core-data/src/hooks/ProgressiveSearch.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import TypesenseUtils from '../utils/Typesense';
1212

1313
type OnCompleteCallback = (results: Array<SearchResult>) => void;
1414

15-
const useProgressiveSearch = (infiniteHits) => {
15+
const useProgressiveSearch = (infiniteHits, transformResults = null) => {
1616
const [cachedHits, setCachedHits] = useState(TypesenseUtils.createCachedHits([]));
1717

1818
const lastSearchState = useRef<any>();
@@ -59,11 +59,28 @@ const useProgressiveSearch = (infiniteHits) => {
5959
return !dequal(a, b);
6060
};
6161

62+
/**
63+
* Returns the transformed hits if the callback is provided. Otherwise, the untransformed hits are returned.
64+
*
65+
* @param results
66+
*
67+
* @returns {*}
68+
*/
69+
const getHits = (results) => {
70+
let value = results.hits;
71+
72+
if (transformResults) {
73+
value = transformResults(value);
74+
}
75+
76+
return value;
77+
};
78+
6279
useEffect(() => {
6380
const { results } = infiniteHits;
6481

6582
const isFirstPage = results.page === 0;
66-
const hits = TypesenseUtils.normalizeResults(results.hits);
83+
const hits = getHits(results);
6784

6885
// Add to cache and load next page
6986
if (isFirstPage && hasStateChanged(results._state, lastSearchState.current, true)) {
@@ -75,8 +92,8 @@ const useProgressiveSearch = (infiniteHits) => {
7592

7693
useEffect(() => {
7794
const { results } = infiniteHits;
95+
const hits = getHits(results);
7896

79-
const hits = TypesenseUtils.normalizeResults(results.hits);
8097
const isLastPage = results.page + 1 >= results.nbPages;
8198

8299
if (!isLastPage && infiniteHits.showMore) {

packages/core-data/src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export { default as FacetListsGrouped } from './components/FacetListsGrouped';
1313
export { default as FacetSlider } from './components/FacetSlider';
1414
export { default as FacetStateContextProvider } from './components/FacetStateContextProvider';
1515
export { default as FacetTimeline } from './components/FacetTimeline';
16+
export { default as HeaderImage } from './components/HeaderImage';
17+
export { default as KeyValueList } from './components/KeyValueList';
1618
export { default as LayerMenu } from './components/LayerMenu';
1719
export { default as LoadAnimation } from './components/LoadAnimation';
1820
export { default as MediaGallery } from './components/MediaGallery';
@@ -49,6 +51,7 @@ export {
4951
useInstancesService,
5052
useItemsService,
5153
useLoader,
54+
useOrganizationsService,
5255
usePeopleService,
5356
usePlacesService,
5457
useWorksService
@@ -66,6 +69,7 @@ export {
6669
export { default as EventsService } from './services/Events';
6770
export { default as InstancesService } from './services/Instances';
6871
export { default as ItemsService } from './services/Items';
72+
export { default as OrganizationsService } from './services/Organizations';
6973
export { default as PeopleService } from './services/People';
7074
export { default as PlacesService } from './services/Places';
7175
export { default as WorksService } from './services/Works';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @flow
2+
3+
import BaseService from './BaseService';
4+
5+
/**
6+
* Class responsible for making API calls to the Core Data `organizations` API endpoint.
7+
*/
8+
class Organizations extends BaseService {
9+
/**
10+
* Returns the organizations route name.
11+
*
12+
* @returns {string}
13+
*/
14+
getRoute() {
15+
return 'organizations';
16+
}
17+
}
18+
19+
export default Organizations;

0 commit comments

Comments
 (0)