Commit 88a5ab5c authored by David Björkheim's avatar David Björkheim
Browse files

DEICH-5558 Deichman.no: Data fetching for other publications

parent b3dd3f09
import React from "react";
import { Accordion, Block } from "@digibib/deichman-ui";
export default function PublicationAccordionContainer({ publicationId }) {
return (
<Block top={8}>
<Accordion text="Andre utgaver" openByDefault large showDividers>
<div>TODO IMPLEMENT ME</div>
{/* <Block top={5}>
<ActiveFilters type="publication" />
</Block>
<PublicationList
query={query}
items={workData.publications}
favourites={favourites}
parent={workData}
onReserve={this.handleReserve}
onFavourite={this.handleFavourite}
onShowDetails={this.handleShowDetails}
userCategory={userCategory}
tjenesteKatalogUrl={tjenesteKatalogUrl}
publicationId={publicationId}
/> */}
</Accordion>
</Block>
);
}
import React, { Component } from "react";
import autoBind from "auto-bind";
import React from "react";
import PropTypes from "prop-types";
import {
......@@ -10,142 +9,43 @@ import MT_WEIGHTS from "../../constants/mediaTypeWeights";
import LNG_WEIGHTS from "../../constants/languageWeights";
import PublicationCard from "../PublicationCard";
import { Block, ShowMore } from "@digibib/deichman-ui";
import { translations as TRANSLATIONS } from "../../constants/translations";
import "./styles.css";
function ensureArray(obj) {
if (!obj || obj === null) {
return [];
}
if (Array.isArray(obj)) {
return obj;
}
return [obj];
}
class PublicationList extends Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
expanded: false
};
}
handleExpand() {
this.setState({
expanded: true
});
}
filterAndSortItems() {
const { expanded } = this.state;
const { query, items, limited, publicationId } = this.props;
const showPreview = limited && !expanded;
const activeFilters = [
...getActiveFiltersFromUrlLegacy(query),
...getActiveCustomSearchFilters(query)
];
const filterValuesByType = activeFilters.reduce((acc, f) => {
if (!acc[f.type]) {
acc[f.type] = [];
}
acc[f.type].push(f.paramValue || f.value);
return acc;
}, {});
const processed = items.filter(pub => {
// Check if publication matches at least one value for every filter type
const isMatch = Object.keys(filterValuesByType).every(type => {
switch (type) {
case "language":
return ensureArray(pub.languages).some(l =>
filterValuesByType[type].includes(TRANSLATIONS[l])
);
case "branch":
return ensureArray(pub.items).some(i =>
filterValuesByType[type].includes(i.branchcode)
);
case "excludeUnavailable":
return ensureArray(pub.items).some(i => i.available > 0);
case "mediatype":
return [pub.mediaType].some(m =>
filterValuesByType[type].includes(TRANSLATIONS[m])
);
case "format":
return ensureArray(pub.formats).some(f =>
filterValuesByType[type].includes(TRANSLATIONS[f])
);
case "yearFrom":
return pub.publicationYear >= filterValuesByType[type];
case "yearTo":
return pub.publicationYear <= filterValuesByType[type];
default:
return true;
}
});
return isMatch;
});
// Group and sort by MediaType, then by language,
// but always sort selected publication first
const sorted = processed.sort(
(a, b) =>
(a.id === publicationId || 1000) - (b.id === publicationId || 1000) ||
MT_WEIGHTS[a.mediaType] - MT_WEIGHTS[b.mediaType] ||
((a.languages && LNG_WEIGHTS[a.languages[0]]) || 100) -
((b.languages && LNG_WEIGHTS[b.languages[0]]) || 100) ||
b.publicationYear - a.publicationYear
);
return showPreview ? sorted.slice(0, 6) : sorted;
}
render() {
const {
parent,
limited,
onFavourite,
favourites,
onReserve,
tjenesteKatalogUrl,
userCategory
} = this.props;
const { expanded } = this.state;
const items = this.filterAndSortItems();
return (
<section className="publication-list">
<ul className="publication-list__items">
{items.map(item => (
<li className="publication-list__item" key={item.id}>
<PublicationCard
data={item}
parent={parent}
flags={item.flags}
isFavourited={favourites.includes(item.recordId)}
onFavourite={() => onFavourite(item.recordId)}
onReserve={() => onReserve(item.recordId)}
tjenesteKatalogUrl={tjenesteKatalogUrl}
userCategory={userCategory}
/>
</li>
))}
</ul>
{limited && !expanded && (
<Block top={6}>
<ShowMore text="Se flere" onClick={this.handleExpand} />
</Block>
)}
</section>
);
}
export default function PublicationList({
parent,
onFavourite,
favourites,
onReserve,
tjenesteKatalogUrl,
userCategory,
query,
publications,
publicationId
}) {
const dispItems = filterAndSortItems({ query, publications, publicationId });
return (
<section className="publication-list">
<ul className="publication-list__items">
{dispItems.map(item => (
<li className="publication-list__item" key={item.id}>
<PublicationCard
data={item}
parent={parent}
flags={item.flags}
isFavourited={favourites.includes(item.recordId)}
onFavourite={() => onFavourite(item.recordId)}
onReserve={() => onReserve(item.recordId)}
tjenesteKatalogUrl={tjenesteKatalogUrl}
userCategory={userCategory}
/>
</li>
))}
</ul>
</section>
);
}
PublicationList.defaultProps = {
......@@ -158,10 +58,9 @@ PublicationList.defaultProps = {
};
PublicationList.propTypes = {
items: PropTypes.arrayOf(PropTypes.object),
publications: PropTypes.arrayOf(PropTypes.object),
query: PropTypes.object,
parent: PropTypes.object,
limited: PropTypes.bool,
favourites: PropTypes.array,
onFavourite: PropTypes.func.isRequired,
onReserve: PropTypes.func.isRequired,
......@@ -170,4 +69,76 @@ PublicationList.propTypes = {
publicationId: PropTypes.string.isRequired
};
export default PublicationList;
// --------- Utils below ------------------
function ensureArray(obj) {
if (!obj || obj === null) {
return [];
}
if (Array.isArray(obj)) {
return obj;
}
return [obj];
}
function filterAndSortItems({ query, publications, publicationId }) {
const activeFilters = [
...getActiveFiltersFromUrlLegacy(query),
...getActiveCustomSearchFilters(query)
];
const filterValuesByType = activeFilters.reduce((acc, f) => {
if (!acc[f.type]) {
acc[f.type] = [];
}
acc[f.type].push(f.paramValue || f.value);
return acc;
}, {});
const processed = publications.filter(pub => {
// Check if publication matches at least one value for every filter type
const isMatch = Object.keys(filterValuesByType).every(type => {
switch (type) {
case "language":
return ensureArray(pub.languages).some(l =>
filterValuesByType[type].includes(TRANSLATIONS[l])
);
case "branch":
return ensureArray(pub.items).some(i =>
filterValuesByType[type].includes(i.branchcode)
);
case "excludeUnavailable":
return ensureArray(pub.items).some(i => i.available > 0);
case "mediatype":
return [pub.mediaType].some(m =>
filterValuesByType[type].includes(TRANSLATIONS[m])
);
case "format":
return ensureArray(pub.formats).some(f =>
filterValuesByType[type].includes(TRANSLATIONS[f])
);
case "yearFrom":
return pub.publicationYear >= filterValuesByType[type];
case "yearTo":
return pub.publicationYear <= filterValuesByType[type];
default:
return true;
}
});
return isMatch;
});
// Group and sort by MediaType, then by language,
// but always sort selected publication first
const sorted = processed.sort(
(a, b) =>
(a.id === publicationId || 1000) - (b.id === publicationId || 1000) ||
MT_WEIGHTS[a.mediaType] - MT_WEIGHTS[b.mediaType] ||
((a.languages && LNG_WEIGHTS[a.languages[0]]) || 100) -
((b.languages && LNG_WEIGHTS[b.languages[0]]) || 100) ||
b.publicationYear - a.publicationYear
);
return sorted;
}
import React, { useEffect, useState } from "react";
import { Accordion, Block, Loader } from "@digibib/deichman-ui";
import { useDispatch, useSelector } from "react-redux";
import ActiveFilters from "../ActiveFilters";
import PublicationList from "./PublicationList";
import { useRouter } from "next/router";
export default function PublicationsAccordionContainer({ publication }) {
const [isLoading, setLoading] = useState(true);
const [copies, setCopies] = useState({});
const dispatch = useDispatch();
const favourites = useSelector(state => state.favourites.biblioNumbers);
const onFavourite = recordId => dispatch(toggleFavourites({ recordId }));
const userCategory = useSelector(state => state.auth.userData.category);
const tjenesteKatalogUrl = useSelector(
state => state.application.urls.tjenestekatalog
);
const { query } = useRouter();
const getCopies = id => {
return (
copies[publication.id] &&
copies[publication.id][id] &&
copies[publication.id][id].items
);
};
const decoratedPublications = publication.work.publications
.map(p => ({
...p,
items: getCopies(p.recordId)
}))
.filter(
p => p.mediaType === publication.mediaType && p.id !== publication.id
);
return (
<Block top={8}>
<Accordion text="Andre utgivelser" closedByDefault large showDividers>
<>
<LoadDataTrigger
publication={publication}
setLoading={setLoading}
setCopies={setCopies}
copies={copies}
/>
{isLoading && (
<Block top={6} responsive>
<Loader />
</Block>
)}
{!isLoading && decoratedPublications.length > 0 && (
<Block top={5}>
<ActiveFilters type="publication" />
<PublicationList
query={query}
publications={decoratedPublications}
favourites={favourites}
parent={publication.work}
onReserve={Function.prototype} //TODO fix this post DEICH-5554 merge
onFavourite={onFavourite}
onShowDetails={Function.prototype} //TODO fix this post DEICH-5554 merge
userCategory={userCategory}
tjenesteKatalogUrl={tjenesteKatalogUrl}
publicationId={publication.id}
/>
</Block>
)}
{!isLoading && decoratedPublications.length === 0 && (
<Block top={5}> Her fantes det ingen utgaver å vise</Block>
)}
</>
</Accordion>
</Block>
);
}
function LoadDataTrigger(props) {
const id = props?.publication?.id;
const loadCopies = async (
{ publication, setLoading, setCopies, copies },
controls
) => {
if (!copies[publication.id]) {
!controls.canceled && setLoading(true);
try {
const res = await fetch(
`/api/resources/copies?id=${publication.work.publications
.map(p => p.recordId)
.join(",")}`
);
const newCopies = await res.json();
!controls.canceled &&
setCopies({
...copies,
[publication.id]: newCopies
});
} catch (err) {
console.error(err);
}
!controls.canceled && setLoading(false);
}
};
useEffect(
() => {
const controls = { canceled: false };
loadCopies(props, controls);
return () => (controls.canceled = true);
},
[id]
);
return null;
}
......@@ -14,8 +14,8 @@ import RecommendationAccordion from "../../components/RecommendationAccordion/Re
import WorkDetailsAccordionContainer from "../../components/WorkDetails/WorkDetailsAccordionContainer";
import PublicationPartsAccordion from "../../components/PublicationParts";
import WorkHeroContainer from "../../components/WorkHero/WorkHeroContainer";
import PublicationAccordionContainer from "../../components/PublicationList/PublicationAccordionContainer";
import PublicationRelatedContent from "../../components/PublicationRelatedContent/PublicationRelatedContent";
import PublicationsAccordionContainer from "../../components/PublicationList/PublicationsAccordionContainer";
import { useRouter } from "next/router";
class PublicationPage extends React.Component {
......@@ -107,7 +107,7 @@ class PublicationPage extends React.Component {
<RecommendationAccordion recommendations={recommendations} />
<WorkDetailsAccordionContainer publication={publication} />
<PublicationPartsAccordion publication={publication} />
<PublicationAccordionContainer />
<PublicationsAccordionContainer publication={publication} />
</Container>
<Container>
<PublicationRelatedContent publication={publication} />
......
......@@ -690,4 +690,18 @@ routes.get("/publication/:publicationId/biblio", async (req, res) => {
res.json({});
});
routes.get("/copies/", async (req, res) => {
const deichmanCallId = req.headers[CALL_ID_HEADER];
const { id: idString } = req.query;
const ids = `${idString}`.split(",");
const info = await getWorkItemsByRecordIds(
ids,
req.query.categorycode,
deichmanCallId
);
res.json(info);
});
module.exports = routes;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment