Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hold åpen versjonsvelger #145

Merged
merged 30 commits into from
Mar 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2f276e0
Implement version selector state persistence and URL updates in Conte…
bdahle Mar 13, 2025
e982a01
Refactor version selector state management in Content component and i…
bdahle Mar 13, 2025
d60d221
Enhance version selector caching and state management in Content comp…
bdahle Mar 13, 2025
34bd882
Refactor cache management in Content and VersionSelector components
bdahle Mar 13, 2025
e6085c1
Refactor cache management in Content component
bdahle Mar 13, 2025
ba86b3b
Enhance cache management in Content component
bdahle Mar 13, 2025
e5f723f
Update rendering logic for VersionSelector in Content component
bdahle Mar 13, 2025
e2d215e
Refactor URL management in Content component
bdahle Mar 13, 2025
313e142
Refactor version selector state management in VersionSelector component
bdahle Mar 13, 2025
31bdc5e
Refactor cache and search management in Content and VersionSelector c…
bdahle Mar 13, 2025
cf0aa3e
Refactor URL and version handling in Content component
bdahle Mar 13, 2025
cafcab8
Revert "Refactor URL and version handling in Content component"
bdahle Mar 13, 2025
14c2b86
Merge branch 'main' into keep-open-version-selector-2
bdahle Mar 19, 2025
c3430cd
Merge branch 'main' into keep-open-version-selector-2
bdahle Mar 20, 2025
529d29c
fjern kommentarer og ||
bdahle Mar 20, 2025
1297c75
hindre dobbel linje og hopping i versjonsvelgeren
bdahle Mar 20, 2025
f6c1f2c
test cached versjon i åpne-knappen
bdahle Mar 20, 2025
e7df092
cache tittel og url
bdahle Mar 20, 2025
86eae8e
cache "Visning" og prøv å forenkle det hele
bdahle Mar 20, 2025
73f4d40
Revert "cache "Visning" og prøv å forenkle det hele"
bdahle Mar 20, 2025
e44edce
Refactor Content component to use optional chaining for safer data ac…
bdahle Mar 20, 2025
1083c4d
forsøk cache visning
bdahle Mar 20, 2025
b761ac1
Revert "forsøk cache visning"
bdahle Mar 20, 2025
fae8337
fjern kommentarer
bdahle Mar 20, 2025
073c1db
legg til knapp for å lukke versjonsvelgeren
bdahle Mar 20, 2025
c63494b
bytt tilbake til pushState
bdahle Mar 21, 2025
3f46412
Refactor version selector logic for improved readability and maintain…
bdahle Mar 21, 2025
4db9bfa
revert til å resette søk når panelet lukkes
bdahle Mar 21, 2025
23d8668
inline display name og path
bdahle Mar 21, 2025
ba4401e
Refactor VersionSelectorCache to use a default cache item and improve…
bdahle Mar 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 104 additions & 22 deletions xp-archive/client/content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { VersionSelector } from 'client/versionSelector/VersionSelector';
import { ContentView } from '../contentView/ContentView';
import { formatTimestamp } from '@common/shared/timestamp';
import { EmptyState } from '@common/shared/EmptyState/EmptyState';
import {
setCachedVersionSelector,
getCachedVersionSelector,
clearCachedVersionSelector,
} from 'client/versionSelector/VersionSelectorCache';

import style from './Content.module.css';

Expand All @@ -18,15 +23,12 @@ const getDefaultView = (isWebpage: boolean, hasAttachment: boolean): ViewVariant
return undefined;
};

const updateContentUrl = (nodeId: string, locale: string, versionId?: string) => {
const newUrl = `${xpArchiveConfig.basePath}/${nodeId}/${locale}/${versionId ?? ''}`;
window.history.pushState({}, '', newUrl);
};

export const Content = () => {
const { selectedContentId, selectedLocale, selectedVersion, setSelectedVersion } =
useAppState();

const prevContentIdRef = React.useRef(selectedContentId);

useEffect(() => {
const pathSegments = window.location.pathname.split('/');
if (pathSegments.length >= 5) {
Expand All @@ -43,21 +45,58 @@ export const Content = () => {
});

useEffect(() => {
if (selectedVersion) {
updateContentUrl(selectedContentId ?? '', selectedLocale, selectedVersion);
} else if (data?.versions?.[0]) {
const latestVersionId = data.versions[0].versionId;
setSelectedVersion(latestVersionId);
updateContentUrl(selectedContentId ?? '', selectedLocale, latestVersionId);
const versionId = selectedVersion ?? data?.versions?.[0]?.versionId;
if (versionId) {
if (!selectedVersion) {
setSelectedVersion(versionId);
}
const newUrl = `${xpArchiveConfig.basePath}/${selectedContentId}/${selectedLocale}/${versionId}`;
window.history.pushState({}, '', newUrl);
}
}, [data, selectedContentId, selectedLocale, selectedVersion]);

const isWebpage = !!data?.html && !data.json.attachment;
const hasAttachment = !!data?.json.attachment;
const isWebpage = !!data?.html && !data?.json?.attachment;
const hasAttachment = !!data?.json?.attachment;
const [selectedView, setSelectedView] = useState<ViewVariant | undefined>(
getDefaultView(isWebpage, hasAttachment)
);
const [isVersionPanelOpen, setIsVersionPanelOpen] = useState(false);

const [versionSelectorCache, setVersionSelectorCache] = useState(() => {
const cache = getCachedVersionSelector(selectedContentId ?? '');
return {
component: cache.component,
versions: cache.versions,
isOpen: cache.isOpen,
};
});

const [cachedDisplayData, setCachedDisplayData] = useState({
displayName: '',
path: '',
});

useEffect(() => {
if (prevContentIdRef.current && prevContentIdRef.current !== selectedContentId) {
clearCachedVersionSelector(prevContentIdRef.current);
}

if (data?.versions && selectedContentId) {
setVersionSelectorCache((prev) => ({
component: null,
versions: data.versions,
isOpen: prev.isOpen,
}));

if (data.json?.displayName || data.json?._path) {
setCachedDisplayData({
displayName: data.json.displayName || '',
path: data.json._path || '',
});
}
}

prevContentIdRef.current = selectedContentId;
}, [selectedContentId, data?.versions, data?.json]);

useEffect(() => {
setSelectedView(getDefaultView(isWebpage, hasAttachment));
Expand All @@ -68,6 +107,15 @@ export const Content = () => {
}`;

const getVersionDisplay = () => {
if (selectedVersion && versionSelectorCache.versions.length > 0) {
const cachedVersion = versionSelectorCache.versions.find(
(v) => v.versionId === selectedVersion
);
if (cachedVersion?.timestamp) {
return formatTimestamp(cachedVersion.timestamp);
}
}

if (selectedVersion && data?.versions) {
return formatTimestamp(
data.versions.find((v) => v.versionId === selectedVersion)?.timestamp ?? ''
Expand All @@ -91,15 +139,49 @@ export const Content = () => {
variant={'secondary'}
icon={<SidebarRightIcon />}
iconPosition={'right'}
onClick={() => setIsVersionPanelOpen(true)}
onClick={() => {
setVersionSelectorCache((prev) => ({
...prev,
isOpen: true,
}));
}}
>
{getVersionDisplay()}
</Button>
<VersionSelector
versions={data?.versions || []}
isOpen={isVersionPanelOpen}
onClose={() => setIsVersionPanelOpen(false)}
/>

{versionSelectorCache.component
? versionSelectorCache.component
: (() => {
const versionSelectorVersions =
versionSelectorCache.versions.length > 0
? versionSelectorCache.versions
: data?.versions || [];

const handleClose = () => {
setVersionSelectorCache((prev) => ({
...prev,
isOpen: false,
}));
};

const handleMount = (component: React.ReactNode) => {
setCachedVersionSelector(
selectedContentId ?? '',
component,
versionSelectorVersions,
versionSelectorCache.isOpen
);
};

return (
<VersionSelector
versions={versionSelectorVersions}
isOpen={versionSelectorCache.isOpen}
onClose={handleClose}
onMount={handleMount}
/>
);
})()}
</div>
<div className={style.viewSelector}>
<Label className={style.label}>Visning</Label>
Expand Down Expand Up @@ -128,10 +210,10 @@ export const Content = () => {

<div className={style.titleAndUrl}>
<Heading size={'medium'} level={'2'}>
{data?.json.displayName ?? ''}
{data?.json?.displayName || cachedDisplayData.displayName || 'Laster...'}
</Heading>
<div className={style.url}>
<Detail>{data?.json._path ?? ''}</Detail>
<Detail>{data?.json?._path || cachedDisplayData.path || ''}</Detail>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
}

.panel {
display: flex;
flex-direction: column;
position: relative;
z-index: 1;
width: 400px;
width: 460px;
height: 100vh;
background: var(--a-surface-default);
box-shadow: 4px 0 8px rgba(0, 0, 0, 0.1);
Expand Down
11 changes: 11 additions & 0 deletions xp-archive/client/versionSelector/VersionSelector.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@
font-weight: var(--a-font-weight-bold);
}
}

.closeButton {
position: sticky;
bottom: 1rem;
margin-top: 1.75rem;

width: fit-content;
border-radius: 99px;
background-color: var(--a-surface-inverted);
align-self: center;
}
26 changes: 21 additions & 5 deletions xp-archive/client/versionSelector/VersionSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { CheckmarkIcon, XMarkIcon } from '@navikt/aksel-icons';
import { Heading, Button, Search } from '@navikt/ds-react';
import { VersionReference } from 'shared/types';
import { formatTimestamp } from '@common/shared/timestamp';
import { useAppState } from 'client/context/appState/useAppState';
import { SlidePanel } from './SlidePanel/SlidePanel';
import { classNames } from '@common/client/utils/classNames';
import style from './VersionSelector.module.css';
import { CheckmarkIcon } from '@navikt/aksel-icons';

type Props = {
versions: VersionReference[];
isOpen: boolean;
onClose: () => void;
onMount?: (component: React.ReactNode) => void;
};

type VersionButtonProps = {
Expand All @@ -32,7 +33,7 @@ const VersionButton = ({ isSelected, onClick, children }: VersionButtonProps) =>
</Button>
);

export const VersionSelector = ({ versions, isOpen, onClose }: Props) => {
export const VersionSelector = ({ versions, isOpen, onClose, onMount }: Props) => {
const [searchQuery, setSearchQuery] = useState('');
const { setSelectedContentId, selectedVersion, setSelectedVersion } = useAppState();

Expand All @@ -45,14 +46,13 @@ export const VersionSelector = ({ versions, isOpen, onClose }: Props) => {
const nodeId = versions.find((v) => v.versionId === versionId)?.nodeId;
if (nodeId) setSelectedContentId(nodeId);
setSelectedVersion(versionId);
handleClose();
};

const filteredVersions = versions.filter((version) =>
formatTimestamp(version.timestamp).toLowerCase().includes(searchQuery.toLowerCase())
);

return (
const component = (
<SlidePanel isOpen={isOpen} onClose={handleClose}>
<Heading size="medium" spacing>
Versjoner
Expand All @@ -78,6 +78,22 @@ export const VersionSelector = ({ versions, isOpen, onClose }: Props) => {
</VersionButton>
))}
</div>
<Button
className={style.closeButton}
variant="primary-neutral"
icon={<XMarkIcon />}
onClick={handleClose}
>
Lukk versjonsvelger
</Button>
</SlidePanel>
);

useEffect(() => {
if (onMount) {
onMount(component);
}
}, [versions, isOpen, searchQuery, selectedVersion]);

return component;
};
45 changes: 45 additions & 0 deletions xp-archive/client/versionSelector/VersionSelectorCache.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { VersionReference } from 'shared/types';

type VersionSelectorCacheItem = {
component: React.ReactNode | null;
versions: VersionReference[];
isOpen: boolean;
};

const DEFAULT_CACHE: VersionSelectorCacheItem = {
component: null,
versions: [],
isOpen: false,
};

const contentCache: Record<string, VersionSelectorCacheItem> = {};

export const setCachedVersionSelector = (
contentId: string,
component: React.ReactNode,
versions: VersionReference[],
isOpen: boolean
) => {
Object.keys(contentCache).forEach((key) => {
if (key !== contentId) {
delete contentCache[key];
}
});

contentCache[contentId] = {
component,
versions,
isOpen,
};
};

export const getCachedVersionSelector = (contentId: string): VersionSelectorCacheItem => {
return contentCache[contentId] || DEFAULT_CACHE;
};

export const clearCachedVersionSelector = (contentId: string): void => {
if (contentId in contentCache) {
delete contentCache[contentId];
}
};
Loading