From a23e1095c5dedb2ec1e4f58dde005b85fea2d09e Mon Sep 17 00:00:00 2001 From: Kasper Birch Date: Thu, 28 Nov 2024 14:54:03 +0100 Subject: [PATCH] Add `useGetWorkUrlFromIdentifier` to support material linking from loans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since all data from loans comes from Publizon, we don’t have a `workId`, which is required to link to the material. Therefore, I use the `useComplexSearchWithPaginationQuery` to find the work using the ISBN (identifier) and construct the `workId` into a URL, e.g., `/work/work-of:870970-basis:62986115`. Additionally, if it finds the material type, it adds that as a parameter. --- src/apps/loan-list/modal/material-details.tsx | 26 +++------ .../storybook/materialDetailsModalArgs.ts | 16 ++--- src/core/utils/useGetWorkUrlFromIdentifier.ts | 58 +++++++++++++++++++ 3 files changed, 74 insertions(+), 26 deletions(-) create mode 100644 src/core/utils/useGetWorkUrlFromIdentifier.ts diff --git a/src/apps/loan-list/modal/material-details.tsx b/src/apps/loan-list/modal/material-details.tsx index 090f4b5c6b..f3a99b6ffa 100644 --- a/src/apps/loan-list/modal/material-details.tsx +++ b/src/apps/loan-list/modal/material-details.tsx @@ -2,7 +2,6 @@ import React, { FC, useState } from "react"; import ReservationIcon from "@danskernesdigitalebibliotek/dpl-design-system/build/icons/collection/Reservations.svg"; import LoansIcon from "@danskernesdigitalebibliotek/dpl-design-system/build/icons/collection/Loans.svg"; import EbookIcon from "@danskernesdigitalebibliotek/dpl-design-system/build/icons/collection/Ebook.svg"; -import ExternalLinkIcon from "@danskernesdigitalebibliotek/dpl-design-system/build/icons/buttons/icon-btn-external-link.svg"; import { useText } from "../../../core/utils/text"; import { isDigital } from "../utils/helpers"; import { materialIsOverdue } from "../../../core/utils/helpers/general"; @@ -22,6 +21,7 @@ import { RequestStatus } from "../../../core/utils/types/request"; import { RenewedLoanV2 } from "../../../core/fbs/model"; import RenewalModalMessage from "../../../components/renewal/RenewalModalMessage"; import { formatDate } from "../../../core/utils/helpers/date"; +import useGetWorkUrlFromIdentifier from "../../../core/utils/useGetWorkUrlFromIdentifier"; interface MaterialDetailsProps { loan: LoanType | null; @@ -33,6 +33,7 @@ const MaterialDetails: FC = ({ material, modalId }) => { + const { workUrl } = useGetWorkUrlFromIdentifier(loan?.identifier); const [renewingStatus, setRenewingStatus] = useState("idle"); const [renewingResponse, setRenewingResponse] = useState< RenewedLoanV2[] | null @@ -40,7 +41,6 @@ const MaterialDetails: FC = ({ const t = useText(); const u = useUrls(); - const ereolenMyPageUrl = u("ereolenMyPageUrl"); const viewFeesAndCompensationRatesUrl = u("viewFeesAndCompensationRatesUrl"); if (!loan) { @@ -119,18 +119,13 @@ const MaterialDetails: FC = ({ renewalStatusList={renewalStatusList} /> )} - {isDigital(loan) && ( + {isDigital(loan) && workUrl && (
- {t("materialDetailsGoToEreolenText")} - + {t("materialDetailsGoToMaterialText")}
)} @@ -186,18 +181,13 @@ const MaterialDetails: FC = ({ renewalStatusList={renewalStatusList} /> )} - {isDigital(loan) && ( + {isDigital(loan) && workUrl && (
- {t("materialDetailsGoToEreolenText")} - + {t("materialDetailsGoToMaterialText")}
)} diff --git a/src/core/storybook/materialDetailsModalArgs.ts b/src/core/storybook/materialDetailsModalArgs.ts index a85471076f..8bb1fdba40 100644 --- a/src/core/storybook/materialDetailsModalArgs.ts +++ b/src/core/storybook/materialDetailsModalArgs.ts @@ -42,10 +42,10 @@ export const argTypes = { defaultValue: { summary: "Expired" } } }, - materialDetailsGoToEreolenText: { + materialDetailsGoToMaterialText: { table: { type: { summary: "text" }, - defaultValue: { summary: "Go to eReolen" } + defaultValue: { summary: "Go to material" } }, control: { type: "text" } }, @@ -77,10 +77,10 @@ export const argTypes = { }, control: { type: "text" } }, - ereolenMyPageUrl: { + materialUrl: { table: { type: { summary: "text" }, - defaultValue: { summary: "https://unsplash.com/photos/wd6YQy0PJt8" } // open source image of a red panda + defaultValue: { summary: "work/:workid" } }, control: { type: "text" } } @@ -94,12 +94,12 @@ export default { materialDetailsMaterialNumberLabelText: "Material Item Number", materialDetailsLinkToPageWithFeesText: "Read more about fees", materialDetailsOverdueText: "Expired", - materialDetailsGoToEreolenText: "Go to eReolen", + materialDetailsGoToMaterialText: "Go to material", materialDetailsDigitalDueDateLabelText: "Expires", materialDetailsRenewLoanButtonText: "Renew your loan", feesPageUrl: "/user/me/fees", viewFeesAndCompensationRatesUrl: "https://unsplash.com/photos/wd6YQy0PJt8", // open source image of a red panda - ereolenMyPageUrl: "https://unsplash.com/photos/wd6YQy0PJt8" // open source image of a red panda + materialUrl: "work/:workid" }; export interface MaterialDetailsModalProps { @@ -110,8 +110,8 @@ export interface MaterialDetailsModalProps { materialDetailsLinkToPageWithFeesText: string; materialDetailsOverdueText: string; feesPageUrl: string; - ereolenMyPageUrl: string; - materialDetailsGoToEreolenText: string; + materialUrl: string; + materialDetailsGoToMaterialText: string; materialDetailsDigitalDueDateLabelText: string; materialDetailsRenewLoanButtonText: string; } diff --git a/src/core/utils/useGetWorkUrlFromIdentifier.ts b/src/core/utils/useGetWorkUrlFromIdentifier.ts new file mode 100644 index 0000000000..88cb985c68 --- /dev/null +++ b/src/core/utils/useGetWorkUrlFromIdentifier.ts @@ -0,0 +1,58 @@ +import { useMemo } from "react"; +import { useComplexSearchWithPaginationQuery } from "../dbc-gateway/generated/graphql"; +import { useUrls } from "./url"; +import { constructMaterialUrl } from "./helpers/url"; +import { WorkId } from "./types/ids"; +import { getMaterialTypes } from "./helpers/general"; +import { Manifestation } from "./types/entities"; + +type UseGetWorkUrlFromIdentifierResult = { + workUrl: URL | null; + isLoading: boolean; + isError: boolean; +}; + +const useGetWorkUrlFromIdentifier = ( + identifier: string | undefined | null +): UseGetWorkUrlFromIdentifierResult => { + const u = useUrls(); + const materialUrl = u("materialUrl"); + + const { data, isLoading, isError } = useComplexSearchWithPaginationQuery( + { + cql: `term.isbn=${identifier}`, + offset: 0, + limit: 1, + filters: {} + }, + { + enabled: Boolean(identifier) + } + ); + + const workUrl = useMemo(() => { + if (!data || !identifier) return null; + + const work = data.complexSearch?.works?.[0]; + if (!work) return null; + + const workId = work.workId as WorkId; + const manifestationWithSameIdentifier = work.manifestations?.all?.find( + (manifestation) => + manifestation.identifiers?.some((id) => id.value === identifier) + ); + const materialType = manifestationWithSameIdentifier + ? getMaterialTypes([manifestationWithSameIdentifier] as Manifestation[]) + : undefined; + + return constructMaterialUrl( + materialUrl, + workId, + materialType ? String(materialType) : undefined + ); + }, [data, identifier, materialUrl]); + + return { workUrl, isLoading, isError }; +}; + +export default useGetWorkUrlFromIdentifier;