Skip to content

Commit 77f9364

Browse files
authored
Merge pull request #2014 from navikt/layer-asset-urls
Setter layer-spesifikke url'er for XP assets
2 parents 9a1bc6a + 7594ae2 commit 77f9364

File tree

9 files changed

+87
-27
lines changed

9 files changed

+87
-27
lines changed

src/components/_common/illustration/static/IllustrationStatic.tsx

+17-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { classNames } from 'utils/classnames';
66
import { buildImageCacheUrl, NextImageProps } from 'components/_common/image/NextImage';
77
import { XpImage } from 'components/_common/image/XpImage';
88
import { useSWRImmutableOnScrollIntoView } from 'utils/fetch/useSWRImmutableOnScrollIntoView';
9+
import { Language } from 'translations';
910

1011
import styleCommon from 'components/_common/illustration/Illustration.module.scss';
1112
import styleStatic from './IllustrationStatic.module.scss';
@@ -16,6 +17,7 @@ type ValidIcon = DefinedIcon & Required<Pick<DefinedIcon, 'mediaUrl'>>;
1617
type StaticIconProps = {
1718
icon: ValidIcon;
1819
isEditorView: boolean;
20+
language: Language;
1921
className?: string;
2022
};
2123

@@ -31,13 +33,13 @@ const fetchSvgData = (url: string) =>
3133
.then((res) => (res.ok ? res.text() : null))
3234
.catch((_) => null);
3335

34-
const SvgIcon = ({ icon, isEditorView, className }: StaticIconProps) => {
36+
const SvgIcon = ({ icon, isEditorView, className, language }: StaticIconProps) => {
3537
const elementId = useId();
3638

3739
const { data: svgData } = useSWRImmutableOnScrollIntoView({
3840
url: buildImageCacheUrl({
3941
...nextImageProps,
40-
src: getMediaUrl(icon.mediaUrl, isEditorView),
42+
src: getMediaUrl(icon.mediaUrl, isEditorView, language),
4143
isEditorView,
4244
}),
4345
fetchFunc: fetchSvgData,
@@ -80,7 +82,7 @@ type Props = {
8082
};
8183

8284
export const IllustrationStatic = ({ illustration, className }: Props) => {
83-
const { editorView } = usePageContentProps();
85+
const { editorView, language } = usePageContentProps();
8486

8587
if (!illustration) {
8688
return null;
@@ -96,10 +98,20 @@ export const IllustrationStatic = ({ illustration, className }: Props) => {
9698
return (
9799
<span className={classNames(styleCommon.image, className)} aria-hidden={'true'}>
98100
{isValidIcon(icon1?.icon) && (
99-
<StaticIcon icon={icon1.icon} isEditorView={!!editorView} className={'back'} />
101+
<StaticIcon
102+
icon={icon1.icon}
103+
isEditorView={!!editorView}
104+
language={language}
105+
className={'back'}
106+
/>
100107
)}
101108
{isValidIcon(icon2?.icon) && (
102-
<StaticIcon icon={icon2.icon} isEditorView={!!editorView} className={'front'} />
109+
<StaticIcon
110+
icon={icon2.icon}
111+
isEditorView={!!editorView}
112+
language={language}
113+
className={'front'}
114+
/>
103115
)}
104116
</span>
105117
);

src/components/_common/image/XpImage.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ type Props = {
1111
NextImageProps;
1212

1313
export const XpImage = ({ imageProps, alt, ...rest }: Props) => {
14-
const { editorView } = usePageContentProps();
14+
const { editorView, language } = usePageContentProps();
1515

16-
const imageUrl = getMediaUrl(imageProps.mediaUrl, !!editorView);
16+
const imageUrl = getMediaUrl(imageProps.mediaUrl, !!editorView, language);
1717
if (!imageUrl) {
1818
return null;
1919
}

src/components/_common/parsed-html/ParsedHtml.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ type Props = {
7878
};
7979

8080
export const ParsedHtml = ({ htmlProps }: Props) => {
81-
const { editorView } = usePageContentProps();
81+
const { editorView, language } = usePageContentProps();
8282

8383
if (!htmlProps) {
8484
return null;
@@ -123,7 +123,7 @@ export const ParsedHtml = ({ htmlProps }: Props) => {
123123
<NextImage
124124
{...props}
125125
alt={attribs.alt || ''}
126-
src={getMediaUrl(attribs.src, !!editorView)}
126+
src={getMediaUrl(attribs.src, !!editorView, language)}
127127
/>
128128
);
129129
}

src/components/_common/qbrick-video/QbrickVideo.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ export const QbrickVideo = (props: QbrickVideoProps) => {
3636

3737
const durationAsString = getTimestampFromDuration(duration);
3838

39-
const imageUrl = poster?.startsWith('http') ? poster : getMediaUrl(poster, !!editorView);
39+
const imageUrl = poster?.startsWith('http')
40+
? poster
41+
: getMediaUrl(poster, !!editorView, contentLanguage);
4042

4143
return (
4244
<div className={style.wrapper}>

src/components/parts/link-panel/LinkPanelPart.tsx

+3-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export type PartConfigLinkPanel = {
2828
} & LinkWithIngressMixin;
2929

3030
export const LinkPanelPart = ({ config }: PartComponentProps<PartType.LinkPanel>) => {
31-
const { editorView } = usePageContentProps();
31+
const { editorView, language } = usePageContentProps();
3232

3333
if (!config) {
3434
return <EditorHelp text={'Tomt lenkepanel'} />;
@@ -40,7 +40,7 @@ export const LinkPanelPart = ({ config }: PartComponentProps<PartType.LinkPanel>
4040

4141
const linkProps = getSelectableLinkProps(link);
4242

43-
const bgUrl = background?.mediaUrl && getMediaUrl(background.mediaUrl, isEditorView);
43+
const bgUrl = background?.mediaUrl && getMediaUrl(background.mediaUrl, isEditorView, language);
4444

4545
const selectedVariant = variant?._selected;
4646
const variantConfig = selectedVariant && variant[selectedVariant];
@@ -86,10 +86,7 @@ export const LinkPanelPart = ({ config }: PartComponentProps<PartType.LinkPanel>
8686
}),
8787
}}
8888
>
89-
<XpImage
90-
imageProps={icon}
91-
maxWidth={isVerticalLayout ? 384 : 64}
92-
/>
89+
<XpImage imageProps={icon} maxWidth={isVerticalLayout ? 384 : 64} />
9390
</div>
9491
)}
9592
<Heading level="2" size="medium" className={style.title}>

src/utils/fetch/fetch-page-props.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const fetchPageProps = async ({
6868

6969
// Media content should redirect to the mediaUrl generated by XP (temporary redirect)
7070
if (isMediaContent(content)) {
71-
const mediaUrl = getMediaUrl(content.mediaUrl, isDraft);
71+
const mediaUrl = getMediaUrl(content.mediaUrl, isDraft, content.language);
7272
if (!mediaUrl) {
7373
return notFoundProps;
7474
}

src/utils/languages.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import { ContentProps } from 'types/content-props/_content-common';
22
import { LanguageProps } from 'types/language';
3+
import { Language } from 'translations';
34

45
export const getContentLanguages = (content: ContentProps): LanguageProps[] =>
56
content.languages || [];
67

78
const norwegianLanguagesSet: ReadonlySet<string> = new Set(['no', 'nn', 'nb']);
89

910
export const isNorwegianLanguage = (language: string) => norwegianLanguagesSet.has(language);
11+
12+
export const pageLanguageToLayerLanguage: { [key in Language]?: Language } = {
13+
nn: 'nn',
14+
se: 'se',
15+
en: 'en',
16+
ru: 'en',
17+
uk: 'en',
18+
pl: 'en',
19+
} as const;

src/utils/urls.ts

+27-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { ContentProps } from 'types/content-props/_content-common';
22
import { logger } from 'srcCommon/logger';
3+
import { Language } from 'translations';
4+
import { pageLanguageToLayerLanguage } from './languages';
35

46
export const appOriginProd = 'https://www.nav.no';
57
export const xpContentPathPrefix = '/www.nav.no';
@@ -91,10 +93,22 @@ export const getInternalAbsoluteUrl = (url: string, isEditorView: boolean) => {
9193
};
9294

9395
// Media url must always be absolute, to prevent internal nextjs routing loopbacks on redirects
94-
export function getMediaUrl(url: string, isEditorView: boolean): string;
95-
export function getMediaUrl(url: string | undefined, isEditorView: boolean): string | undefined;
96-
export function getMediaUrl(url: string | undefined, isEditorView: boolean) {
97-
return url?.replace(
96+
export function getMediaUrl(url: string, isEditorView: boolean, language?: Language): string;
97+
export function getMediaUrl(
98+
url: string | undefined,
99+
isEditorView: boolean,
100+
language?: Language
101+
): string | undefined;
102+
export function getMediaUrl(
103+
url: string | undefined,
104+
isEditorView: boolean,
105+
language: Language = 'no'
106+
) {
107+
if (!url) {
108+
return undefined;
109+
}
110+
111+
return transformToXpLayerUrl(url, isEditorView, language).replace(
98112
internalUrlPrefixPattern,
99113
isEditorView ? `${adminOrigin}${xpDraftPathPrefix}` : xpOrigin
100114
);
@@ -126,3 +140,12 @@ export const routerQueryToXpPathOrId = (routerQuery: string | string[]) => {
126140

127141
return `${xpContentPathPrefix}${path}`;
128142
};
143+
144+
// Direct links to XP assets or services should point to the appropriate layer for the specified language
145+
// The /_/<language> repo mappings are defined in the vhost config on the XP servers
146+
export const transformToXpLayerUrl = (url: string, isEditorView: boolean, language: Language) => {
147+
const path = getInternalRelativePath(url, isEditorView);
148+
const layer = pageLanguageToLayerLanguage[language];
149+
150+
return layer ? path.replace(/^\/_/, `/_/${layer}`) : path;
151+
};

src/utils/usePublicUrl.ts

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
11
import { usePageContentProps } from 'store/pageContext';
2-
import { getInternalRelativePath, isAppUrl, isInternalUrl, stripXpPathPrefix } from './urls';
2+
import {
3+
getInternalRelativePath,
4+
isAppUrl,
5+
isXpUrl,
6+
stripXpPathPrefix,
7+
transformToXpLayerUrl,
8+
} from './urls';
39

410
type ReturnValue = {
511
url: string;
6-
canRouteClientSide: boolean; // If this is true, navigation to the url can be done client-side with next router
12+
canRouteClientSide: boolean; // If true, navigation to the url can be done client-side with next router
713
};
814

915
export const usePublicUrl = (href: string): ReturnValue => {
10-
const { editorView } = usePageContentProps();
16+
const { editorView, language } = usePageContentProps();
1117

12-
if (isInternalUrl(href)) {
18+
if (isXpUrl(href)) {
19+
return {
20+
url: transformToXpLayerUrl(href, !!editorView, language),
21+
canRouteClientSide: false,
22+
};
23+
}
24+
25+
if (isAppUrl(href)) {
1326
const internalPath = getInternalRelativePath(href, !!editorView);
1427
return {
1528
url: internalPath,
16-
canRouteClientSide: isAppUrl(internalPath),
29+
canRouteClientSide: true,
1730
};
1831
}
1932

20-
return { url: stripXpPathPrefix(href) || '/', canRouteClientSide: false };
33+
return {
34+
url: stripXpPathPrefix(href) || '/',
35+
canRouteClientSide: false,
36+
};
2137
};

0 commit comments

Comments
 (0)