diff --git a/src/containers/SearchPage/components/form/StyledSearchComponents.tsx b/src/containers/SearchPage/components/form/StyledSearchComponents.tsx deleted file mode 100644 index 5405a4349a..0000000000 --- a/src/containers/SearchPage/components/form/StyledSearchComponents.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2022-present, NDLA. - * - * This source code is licensed under the GPLv3 license found in the - * LICENSE file in the root directory of this source tree. - * - */ -import styled from "@emotion/styled"; -import { spacing, colors } from "@ndla/core"; - -export const StyledSearchResult = styled.div` - display: flex; -`; - -export const StyledSearchImageContainer = styled.div` - display: inline-block; - width: 10%; - align-self: center; - max-width: 10%; - text-align: center; - & img { - max-height: 9.2rem; - } - & svg { - margin: 1.3rem; - width: 60px; - height: 60px; - } -`; - -export const StyledSearchContent = styled.div` - display: inline-block; - width: 90%; - align-self: center; - padding-left: 1.3rem; -`; - -export const StyledSearchTitle = styled.h1` - font-size: 1.2rem; - margin: 1.3rem 0 0.3rem; - font-weight: 600; - - & svg { - margin-right: 0.2rem; - } -`; - -export const StyledOtherLink = styled.span` - &:not(:last-child) { - &::after { - content: " / "; - } - } -`; - -export const StyledSearchDescription = styled.p` - width: 100%; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - margin: 0 0 1.2rem; -`; - -export const StyledSearchBreadcrumbs = styled.div` - display: flex; - margin-top: 30px; -`; - -export const StyledSearchBreadcrumb = styled.p` - margin-right: ${spacing.small}; - font-size: 0.7rem; - color: black; - text-decoration: underline; -`; - -export const NoShadowAnchor = styled.a` - box-shadow: none; - &:any-link { - color: ${colors.brand.primary}; - } -`; - -export const StyledSearchOtherLink = styled.span` - &:not(:last-child) { - &::after { - content: " / "; - } - } -`; diff --git a/src/containers/SearchPage/components/results/SearchAudio.tsx b/src/containers/SearchPage/components/results/SearchAudio.tsx index 81f11d1c73..d1cdc8115c 100644 --- a/src/containers/SearchPage/components/results/SearchAudio.tsx +++ b/src/containers/SearchPage/components/results/SearchAudio.tsx @@ -7,21 +7,16 @@ */ import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; import { Audio, Podcast } from "@ndla/icons/common"; import { getLicenseByAbbreviation } from "@ndla/licenses"; +import { ListItemContent, ListItemHeading, ListItemImage, ListItemRoot } from "@ndla/primitives"; +import { SafeLink } from "@ndla/safelink"; import { IAudioSummary } from "@ndla/types-backend/audio-api"; import { LicenseLink } from "@ndla/ui"; +import { SearchContentWrapper } from "./SearchContentWrapper"; +import { SearchLanguages } from "./SearchLanguages"; import { useLicenses } from "../../../../modules/draft/draftQueries"; -import { toEditAudio, toEditPodcast } from "../../../../util/routeHelpers"; -import { - StyledSearchContent, - StyledSearchDescription, - StyledSearchImageContainer, - StyledSearchOtherLink, - StyledSearchResult, - StyledSearchTitle, -} from "../form/StyledSearchComponents"; +import { routes } from "../../../../util/routeHelpers"; interface Props { audio: IAudioSummary; @@ -32,28 +27,29 @@ const SearchAudio = ({ audio, locale }: Props) => { const { t } = useTranslation(); const { data: licenses } = useLicenses(); const license = licenses && licenses.find((l) => audio.license === l.license); + return ( - - {audio.audioType === "podcast" ? : - - - {audio.title.title || t("audioSearch.noTitle")} - - - {`${t("searchPage.language")}: `} - {audio.supportedLanguages?.map((lang) => ( - {t(`languages.${lang}`)} - ))} - - {license && } - - + + : ); }; diff --git a/src/containers/SearchPage/components/results/SearchContent.tsx b/src/containers/SearchPage/components/results/SearchContent.tsx index 69a87525a0..ab8b320e7c 100644 --- a/src/containers/SearchPage/components/results/SearchContent.tsx +++ b/src/containers/SearchPage/components/results/SearchContent.tsx @@ -6,51 +6,24 @@ * */ +import { useMemo } from "react"; import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import styled from "@emotion/styled"; -import { fonts } from "@ndla/core"; -import { Concept, Globe } from "@ndla/icons/editor"; +import { CheckLine, Code, Concept, Globe } from "@ndla/icons/editor"; +import { ListItemContent, ListItemHeading, ListItemRoot, Text } from "@ndla/primitives"; +import { SafeLink, SafeLinkIconButton } from "@ndla/safelink"; +import { styled } from "@ndla/styled-system/jsx"; import { IMultiSearchSummary } from "@ndla/types-backend/search-api"; import { Node } from "@ndla/types-taxonomy"; import { ContentTypeBadgeNew, constants } from "@ndla/ui"; -import SearchContentLanguage from "./SearchContentLanguage"; import SearchHighlight from "./SearchHighlight"; -import { EditMarkupLink } from "../../../../components/EditMarkupLink"; -import HeaderStatusInformation from "../../../../components/HeaderWithLanguage/HeaderStatusInformation"; -import { DRAFT_HTML_SCOPE, RESOURCE_TYPE_LEARNING_PATH } from "../../../../constants"; +import { SearchLanguages } from "./SearchLanguages"; +import { SearchListItemImage } from "./SearchListItemImage"; +import HeaderFavoriteStatus from "../../../../components/HeaderWithLanguage/HeaderFavoriteStatus"; +import config from "../../../../config"; +import { DRAFT_HTML_SCOPE, PUBLISHED, RESOURCE_TYPE_LEARNING_PATH } from "../../../../constants"; import { getContentTypeFromResourceTypes, resourceToLinkProps } from "../../../../util/resourceHelpers"; -import { isLearningpath, toEditMarkup } from "../../../../util/routeHelpers"; -import { getExpirationDate } from "../../../ArticlePage/articleTransformers"; +import { isLearningpath, routes } from "../../../../util/routeHelpers"; import { useSession } from "../../../Session/SessionProvider"; -import { - NoShadowAnchor, - StyledSearchBreadcrumb, - StyledSearchBreadcrumbs, - StyledSearchContent, - StyledSearchDescription, - StyledSearchImageContainer, - StyledSearchResult, - StyledSearchTitle, -} from "../form/StyledSearchComponents"; - -const FlexBoxWrapper = styled.div` - display: flex; - flex-flow: row; - margin-right: 0.2rem; - box-shadow: none; - align-items: center; -`; - -const ContentTypeWrapper = styled.div` - margin-right: 0.2em; - margin-top: 10px; -`; - -const DescriptionTitle = styled.p` - margin-bottom: 0; - font-weight: ${fonts.weight.semibold}; -`; interface Props { content: IMultiSearchSummary; @@ -58,56 +31,136 @@ interface Props { responsibleName?: string; subjects: Node[]; } -const Title = StyledSearchTitle.withComponent("h2"); -const NoShadowLink = NoShadowAnchor.withComponent(Link); -const MetaImageComponent = ({ content, locale }: { content: IMultiSearchSummary; locale: string }) => { - const { url, alt } = content.metaImage || {}; - const imageUrl = url ? `${url}?width=200&language=${locale}` : null; - - if (!imageUrl) { - if (content.learningResourceType === "gloss") return ; - if (content.learningResourceType === "concept") return ; - return {alt}; - } - - return {alt}; -}; const SubjectBreadcrumb = ({ content, subjects }: { content: IMultiSearchSummary; subjects: Node[] }) => { - if (content.learningResourceType === "gloss" || content.learningResourceType === "concept") { - const breadcrumbs = subjects.filter((s) => content.conceptSubjectIds?.includes(s.id)); - return ( - <> - {breadcrumbs?.map((breadcrumb) => ( - {breadcrumb.name} - )) || } - - ); - } - - if (content.contexts && content.contexts.length > 0 && content.contexts[0].breadcrumbs) { - return content.contexts[0].breadcrumbs.map((breadcrumb) => ( - - {breadcrumb} - - )); - } else { - return ; - } + const breadcrumbs = useMemo(() => { + if (content.learningResourceType === "gloss" || content.learningResourceType === "concept") { + return subjects.filter((s) => content.conceptSubjectIds?.includes(s.id)).map((bc) => bc.name); + } else return content.contexts?.[0]?.breadcrumbs ?? []; + }, [content.conceptSubjectIds, content.contexts, content.learningResourceType, subjects]); + + if (!breadcrumbs) return null; + + return ( + + {breadcrumbs.join(" > ")} + + ); }; +const BreadcrumbText = styled(Text, { + base: { + justifySelf: "flex-end", + }, +}); + +const ContentWrapper = styled("div", { + base: { + display: "flex", + flexDirection: "column", + gap: "5xsmall", + }, +}); + +const StyledListItemContent = styled(ListItemContent, { + base: { + flexDirection: "column", + gap: "4xsmall", + alignItems: "flex-start", + }, +}); + +const StatusWrapper = styled("div", { + base: { + display: "flex", + gap: "xsmall", + alignSelf: "flex-end", + }, +}); + +const StyledSpan = styled("span", { + base: { + whiteSpace: "nowrap", + }, +}); + +const StyledSearchListItemImage = styled(SearchListItemImage, { + base: { + tabletDown: { + display: "none", + }, + }, +}); + +const StyledListItemRoot = styled(ListItemRoot, { + base: { + tabletDown: { + gap: "0", + }, + }, +}); + +const InfoWrapper = styled("div", { + base: { + display: "flex", + gap: "3xsmall", + alignItems: "center", + }, +}); + +const ListItemHeadingContent = styled(ListItemContent, { + base: { + flexWrap: "wrap", + }, +}); + +const ListItemFooterContent = styled(ListItemContent, { + base: { + alignItems: "flex-end", + flexWrap: "wrap", + }, +}); + +const ListItemMainContent = styled(ListItemContent, { + base: { + alignItems: "flex-start", + tabletDown: { + flexWrap: "wrap", + }, + }, +}); + +const StyledText = styled(Text, { + base: { + lineClamp: "2", + }, +}); + +const conceptTypes = ["concept", "gloss"]; + const SearchContent = ({ content, locale, subjects, responsibleName }: Props) => { const { t } = useTranslation(); const { userPermissions } = useSession(); - const { contexts, metaImage } = content; - const { url, alt } = metaImage || {}; - const imageUrl = url ? `${url}?width=200&language=${locale}` : "/placeholder.png"; - let contentType: string | undefined; - if ((contexts[0]?.resourceTypes?.length ?? 0) > 0) { - contentType = getContentTypeFromResourceTypes(contexts[0].resourceTypes); - } else if (isLearningpath(content.url)) { - contentType = getContentTypeFromResourceTypes([{ id: RESOURCE_TYPE_LEARNING_PATH }]); - } + + const contentType = useMemo(() => { + const resourceTypes = content.contexts[0]?.resourceTypes; + if (resourceTypes?.length) { + return getContentTypeFromResourceTypes(resourceTypes); + } else if (isLearningpath(content.url)) { + return getContentTypeFromResourceTypes([{ id: RESOURCE_TYPE_LEARNING_PATH }]); + } + return undefined; + }, [content.url, content.contexts]); + + const imageData = useMemo(() => { + if (content.learningResourceType === "gloss") { + return { icon: , imageUrl: "" }; + } else if (content.learningResourceType === "concept") { + return { icon: , imageUrl: "" }; + } else { + return { icon: undefined, imageUrl: content.metaImage?.url ?? "/placeholder.png" }; + } + }, [content.learningResourceType, content.metaImage?.url]); const linkProps = resourceToLinkProps(content, content.resultType, locale); @@ -116,82 +169,108 @@ const SearchContent = ({ content, locale, subjects, responsibleName }: Props) => const isLearningpath = contentType === constants.contentTypes.LEARNING_PATH; return t(`form.status.${isLearningpath ? "learningpath_statuses." + status : status}`); }; - const EditMarkup = ( - <> - {content.id && content.resultType === "draft" && userPermissions?.includes(DRAFT_HTML_SCOPE) && ( - - )} - - ); - - const ContentType = ( - <> - {contentType && ( - - - - )}{" "} - - ); const metaDescription = content.metaDescription.metaDescription ?? ""; - const expirationDate = getExpirationDate(content); return ( - - - - - -
- - {ContentType} - - {linkProps && linkProps.href ? ( - <NoShadowAnchor {...linkProps}>{content.title.title}</NoShadowAnchor> - ) : ( - <NoShadowLink to={linkProps.to ?? ""}>{content.title.title}</NoShadowLink> + <StyledListItemRoot variant="list" data-testid="content-search-result"> + <StyledSearchListItemImage + src={imageData.imageUrl} + imageLanguage={locale} + alt={content.metaImage?.alt ?? ""} + fallbackElement={imageData.icon} + sizes="56px" + fallbackWidth={56} + /> + <StyledListItemContent> + <ListItemHeadingContent> + <ListItemHeading asChild consumeCss> + <SafeLink asAnchor={!!linkProps.href} to={linkProps.to ?? linkProps.href} unstyled> + {content.title.title} + </SafeLink> + </ListItemHeading> + <InfoWrapper> + {!!contentType && <ContentTypeBadgeNew contentType={contentType} />} + {content.learningResourceType !== "frontpage-article" && ( + <HeaderFavoriteStatus + id={content.id} + type={content.learningResourceType} + favoriteCount={content.favorited} + /> + )} + </InfoWrapper> + </ListItemHeadingContent> + <ListItemMainContent> + <ContentWrapper> + <SearchLanguages content={content} language={content.title.language} contentType={contentType} /> + <SearchHighlight content={content} locale={locale} /> + {!!metaDescription.length && ( + <> + <Text textStyle="body.small" fontWeight="bold"> + {t("form.name.metaDescription")} + </Text> + <StyledText textStyle="body.small">{metaDescription}</StyledText> + </> + )} + </ContentWrapper> + <InfoWrapper> + {!conceptTypes.includes(contentType ?? "") && + content.id && + content.resultType === "draft" && + userPermissions?.includes(DRAFT_HTML_SCOPE) && ( + <SafeLinkIconButton + size="small" + variant="secondary" + title={t("editMarkup.linkTitle")} + aria-label={t("editMarkup.linkTitle")} + to={routes.editMarkup( + content.id, + content.supportedLanguages.includes(locale) ? locale : content.supportedLanguages[0], + )} + > + <Code /> + </SafeLinkIconButton> )} - {EditMarkup} - - - {content.supportedLanguages.map((lang) => ( - - ))} -
- - {metaDescription !== "" && {t("form.name.metaDescription")}} - {metaDescription} - + + {(content.status?.current === PUBLISHED || content.status?.other.includes(PUBLISHED)) && ( + + + + )} + + + - - -
-
+ + + + {`${t("form.responsible.label")}: `} + + + {responsibleName || t("form.responsible.noResponsible")} + + + + + {`${t("form.workflow.statusLabel")}: `} + + + {statusType() || t("form.status.new")} + + + + + + ); }; diff --git a/src/containers/SearchPage/components/results/SearchContentLanguage.tsx b/src/containers/SearchPage/components/results/SearchContentLanguage.tsx deleted file mode 100644 index 5f5a3db6e8..0000000000 --- a/src/containers/SearchPage/components/results/SearchContentLanguage.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2016-present, NDLA. - * - * This source code is licensed under the GPLv3 license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import styled from "@emotion/styled"; -import { colors } from "@ndla/core"; -import { IMultiSearchSummary } from "@ndla/types-backend/search-api"; -import { resourceToLinkProps } from "../../../../util/resourceHelpers"; -import { StyledOtherLink } from "../form/StyledSearchComponents"; - -const supported = ["en", "nb", "nn"]; - -interface Props { - content: IMultiSearchSummary; - language: string; - contentType?: string; -} - -const StyledAnchor = styled.a` - &:any-link { - color: ${colors.brand.primary}; - } -`; - -const StyledLink = StyledAnchor.withComponent(Link); - -const SearchContentLanguage = ({ language, content, contentType }: Props) => { - const { t } = useTranslation(); - if (!supported.includes(language) || content.title.language === language) { - return null; - } - const linkProps = resourceToLinkProps(content, contentType, language); - - const link = - linkProps && linkProps.href ? ( - {t(`languages.${language}`)} - ) : ( - {t(`languages.${language}`)} - ); - return {link}; -}; - -export default SearchContentLanguage; diff --git a/src/containers/SearchPage/components/results/SearchContentWrapper.tsx b/src/containers/SearchPage/components/results/SearchContentWrapper.tsx new file mode 100644 index 0000000000..7890d58001 --- /dev/null +++ b/src/containers/SearchPage/components/results/SearchContentWrapper.tsx @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2024-present, NDLA. + * + * This source code is licensed under the GPLv3 license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import { styled } from "@ndla/styled-system/jsx"; + +export const SearchContentWrapper = styled("div", { + base: { + display: "flex", + flexDirection: "column", + gap: "xsmall", + }, +}); diff --git a/src/containers/SearchPage/components/results/SearchHighlight.tsx b/src/containers/SearchPage/components/results/SearchHighlight.tsx index 7cd7a17ed8..6aad710624 100644 --- a/src/containers/SearchPage/components/results/SearchHighlight.tsx +++ b/src/containers/SearchPage/components/results/SearchHighlight.tsx @@ -7,8 +7,8 @@ */ import { useTranslation } from "react-i18next"; -import styled from "@emotion/styled"; -import { fonts } from "@ndla/core"; +import { Text } from "@ndla/primitives"; +import { styled } from "@ndla/styled-system/jsx"; import { IMultiSearchSummary } from "@ndla/types-backend/search-api"; interface Props { @@ -16,21 +16,17 @@ interface Props { locale: string; } -const StyledHeading = styled.p` - font-weight: ${fonts.weight.semibold}; - margin-top: 0; - margin-bottom: 0; -`; +const StyledText = styled(Text, { + base: { + cursor: "help", + }, +}); -const StyledHighlights = styled.p` - cursor: help; - margin-top: 0; - margin-bottom: 0; -`; - -const StyledDiv = styled.div` - display: inline-block; -`; +const StyledDiv = styled("div", { + base: { + display: "inline-block", + }, +}); const SearchHighlight = ({ content, locale }: Props) => { const { t } = useTranslation(); @@ -54,8 +50,11 @@ const SearchHighlight = ({ content, locale }: Props) => { return selectedHighlights ? ( - {t("searchPage.highlights.title")} - + {t("searchPage.highlights.title")} + + { const license = licenses && licenses.find((l) => image.copyright.license.license === l.license); return ( - - - {`${image.alttext.alttext}`} - - - - {image.title.title || t("imageSearch.noTitle")} - - - {`${t("searchPage.language")}: `} - {image.supportedLanguages?.map((lang) => ( - {t(`languages.${lang}`)} - ))} - - + + } + sizes="56px" + fallbackWidth={56} + /> + + + + + {image.title.title || t("imageSearch.noTitle")} + + + + + {license && } - - + + ); }; diff --git a/src/containers/SearchPage/components/results/SearchLanguages.tsx b/src/containers/SearchPage/components/results/SearchLanguages.tsx new file mode 100644 index 0000000000..7d0c482e7b --- /dev/null +++ b/src/containers/SearchPage/components/results/SearchLanguages.tsx @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2024-present, NDLA. + * + * This source code is licensed under the GPLv3 license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import { useTranslation } from "react-i18next"; +import { SafeLink } from "@ndla/safelink"; +import { styled } from "@ndla/styled-system/jsx"; +import { ResourceToLinkContent, resourceToLinkProps } from "../../../../util/resourceHelpers"; + +interface Props { + content: ResourceToLinkContent; + language: string; + contentType?: string; + includeCurrent?: boolean; +} + +const LinksWrapper = styled("div", { + base: { + display: "flex", + flexWrap: "wrap", + gap: "3xsmall", + }, +}); + +const LinkWrapper = styled("div", { + base: { + display: "flex", + gap: "3xsmall", + }, +}); + +export const SearchLanguages = ({ content, contentType, language, includeCurrent }: Props) => { + const { t } = useTranslation(); + const languages = includeCurrent + ? content.supportedLanguages + : content.supportedLanguages?.filter((lang) => lang !== language); + + if (!languages?.length) { + return null; + } + + return ( + + {languages.map((language, index) => { + const linkProps = resourceToLinkProps(content, contentType, language); + return ( + + + {t(`languages.${language}`)} + + {index !== languages.length - 1 && / } + + ); + })} + + ); +}; diff --git a/src/containers/SearchPage/components/results/SearchList.tsx b/src/containers/SearchPage/components/results/SearchList.tsx index aeeb4b344d..827769e60e 100644 --- a/src/containers/SearchPage/components/results/SearchList.tsx +++ b/src/containers/SearchPage/components/results/SearchList.tsx @@ -49,14 +49,8 @@ const toResultReturnType = (results: ResultType["results"], type: SearchType): S const SearchList = ({ results, searchObject, type, searching = true, locale, subjects, error }: Props) => { const { t } = useTranslation(); - const editingState = useState(false); - const setEditing = editingState[1]; const [responsibleNames, setResponsibleNames] = useState<(string | undefined)[]>([]); - useEffect(() => { - setEditing(false); - }, [results, setEditing]); - const responsibleIds = useMemo( () => results.map((r) => { @@ -93,7 +87,6 @@ const SearchList = ({ results, searchObject, type, searching = true, locale, sub result={result} locale={locale || result.value.title.language} subjects={subjects} - editingState={editingState} responsibleName={responsibleNames?.[index]} /> ); diff --git a/src/containers/SearchPage/components/results/SearchListItemImage.tsx b/src/containers/SearchPage/components/results/SearchListItemImage.tsx new file mode 100644 index 0000000000..9473fc9b59 --- /dev/null +++ b/src/containers/SearchPage/components/results/SearchListItemImage.tsx @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2024-present, NDLA. + * + * This source code is licensed under the GPLv3 license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import { forwardRef } from "react"; +import { ImageProps, ListItemImage } from "@ndla/primitives"; +import { css } from "@ndla/styled-system/css"; + +const listItemStyle = css.raw({ + minWidth: "102px", + maxWidth: "102px", + minHeight: "77px", + maxHeight: "77px", +}); + +export const SearchListItemImage = forwardRef(({ css: cssProp, ...props }, ref) => ( + +)); diff --git a/src/containers/SearchPage/components/results/SearchPodcastSeries.tsx b/src/containers/SearchPage/components/results/SearchPodcastSeries.tsx index f6b12a7915..6afe9707a6 100644 --- a/src/containers/SearchPage/components/results/SearchPodcastSeries.tsx +++ b/src/containers/SearchPage/components/results/SearchPodcastSeries.tsx @@ -7,17 +7,14 @@ */ import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; +import { Podcast } from "@ndla/icons/common"; +import { ListItemContent, ListItemHeading, ListItemRoot } from "@ndla/primitives"; +import { SafeLink } from "@ndla/safelink"; import { ISeriesSummary } from "@ndla/types-backend/audio-api"; -import { toEditPodcastSeries } from "../../../../util/routeHelpers"; -import { - StyledSearchContent, - StyledSearchDescription, - StyledSearchImageContainer, - StyledSearchOtherLink, - StyledSearchResult, - StyledSearchTitle, -} from "../form/StyledSearchComponents"; +import { SearchContentWrapper } from "./SearchContentWrapper"; +import { SearchLanguages } from "./SearchLanguages"; +import { SearchListItemImage } from "./SearchListItemImage"; +import { routes } from "../../../../util/routeHelpers"; interface Props { series: ISeriesSummary; @@ -25,23 +22,27 @@ interface Props { const SearchPodcastSeries = ({ series }: Props) => { const { t } = useTranslation(); + return ( - - - {`${series.coverPhoto.altText}`} - - - - {series.title.title || t("podcastSearch.noTitle")} - - - {`${t("searchPage.language")}: `} - {series.supportedLanguages?.map((lang) => ( - {t(`languages.${lang}`)} - ))} - - - + + } + /> + + + + + {series.title.title || t("podcastSearch.noTitle")} + + + + + + ); }; diff --git a/src/containers/SearchPage/components/results/SearchResult.tsx b/src/containers/SearchPage/components/results/SearchResult.tsx index 8d083cdf7a..ac1fa982cb 100644 --- a/src/containers/SearchPage/components/results/SearchResult.tsx +++ b/src/containers/SearchPage/components/results/SearchResult.tsx @@ -6,7 +6,6 @@ * */ -import { Dispatch, SetStateAction } from "react"; import { useTranslation } from "react-i18next"; import { IAudioSummary, ISeriesSummary } from "@ndla/types-backend/audio-api"; import { IConceptSummary } from "@ndla/types-backend/concept-api"; @@ -37,11 +36,10 @@ interface Props { result: SearchResultReturnType; locale: string; subjects: Node[]; - editingState: [boolean, Dispatch>]; responsibleName?: string; } -const SearchResult = ({ result, locale, subjects, editingState, responsibleName }: Props) => { +const SearchResult = ({ result, locale, subjects, responsibleName }: Props) => { const { t } = useTranslation(); switch (result.type) { case "content": diff --git a/src/util/resourceHelpers.ts b/src/util/resourceHelpers.ts index 51355f67de..5822573c75 100644 --- a/src/util/resourceHelpers.ts +++ b/src/util/resourceHelpers.ts @@ -48,13 +48,14 @@ const isGlossType = (contentType: string | undefined) => contentType === "gloss" const isAudioType = (contentType: string | undefined) => contentType === "audio"; const isSeriesType = (contentType: string | undefined) => contentType === "series"; +export interface ResourceToLinkContent { + id: number | string; + supportedLanguages?: string[]; + learningResourceType?: string; +} + export const resourceToLinkProps = ( - content: { - id: number; - supportedLanguages?: string[]; - learningResourceType?: string; - contexts?: { contextType: string }[]; - }, + content: ResourceToLinkContent, contentType: string | undefined, locale: string, ) => { diff --git a/src/util/routeHelpers.ts b/src/util/routeHelpers.ts index 04ee517739..5deea9d961 100644 --- a/src/util/routeHelpers.ts +++ b/src/util/routeHelpers.ts @@ -125,12 +125,12 @@ export function toEditNdlaFilm(language?: string) { return `/film/${language ? language : "nb"}`; } -export function toEditConcept(conceptId: number, locale?: string) { +export function toEditConcept(conceptId: number | string, locale?: string) { const path = `/concept/${conceptId}/edit`; return locale ? `${path}/${locale}` : path; } -export function toEditGloss(glossId: number, locale?: string) { +export function toEditGloss(glossId: number | string, locale?: string) { const path = `/gloss/${glossId}/edit`; return locale ? `${path}/${locale}` : path; } @@ -190,7 +190,7 @@ export function toCreateAudioFile() { return "/media/audio-upload/new"; } -export function toEditAudio(audioId: number, language: string) { +export function toEditAudio(audioId: number | string, language: string) { return `/media/audio-upload/${audioId}/edit/${language}`; } @@ -202,11 +202,11 @@ export function toCreatePodcastSeries() { return "/media/podcast-series/new"; } -export function toEditPodcast(audioId: number, language: string) { +export function toEditPodcast(audioId: number | string, language: string) { return `/media/podcast-upload/${audioId}/edit/${language}`; } -export function toEditPodcastSeries(seriesId: number, language: string) { +export function toEditPodcastSeries(seriesId: number | string, language: string) { return `/media/podcast-series/${seriesId}/edit/${language}`; }