Skip to content

Commit

Permalink
feat: Center previous portal when navigating back (#3955)
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr authored Nov 20, 2024
1 parent e396735 commit be24a07
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 20 deletions.
41 changes: 41 additions & 0 deletions editor.planx.uk/src/hooks/useScrollOnPreviousURLMatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useTheme } from "@mui/material/styles";
import { useStore } from "pages/FlowEditor/lib/store";
import { useEffect, useRef } from "react";

const useScrollOnPreviousURLMatch = <T extends HTMLElement>(
urlMatcher: string,
) => {
const previousURL = useStore((state) => state.previousURL);
const ref = useRef<T | null>(null);
const theme = useTheme();

useEffect(() => {
if (!ref.current) return;

const isReturningFromPortal = previousURL?.endsWith(urlMatcher);
if (!isReturningFromPortal) return;

// Center node
ref.current.scrollIntoView({
block: "center",
inline: "center",
});

// Visually highlight node
const keyframes: Keyframe[] = [
{ outline: `4px solid ${theme.palette.action.focus}`, outlineOffset: 0 },
{ outline: `4px solid transparent`, outlineOffset: 0 },
];

const animationOptions: KeyframeAnimationOptions = {
duration: 1500,
easing: "ease-in",
};

ref.current.animate(keyframes, animationOptions);
}, [previousURL, urlMatcher, theme]);

return ref;
};

export default useScrollOnPreviousURLMatch;
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ComponentType } from "@opensystemslab/planx-core/types";
import { ICONS } from "@planx/components/shared/icons";
import classNames from "classnames";
import gql from "graphql-tag";
import useScrollOnPreviousURLMatch from "hooks/useScrollOnPreviousURLMatch";
import { useStore } from "pages/FlowEditor/lib/store";
import React, { useState } from "react";
import { useDrag } from "react-dnd";
Expand All @@ -17,6 +18,8 @@ import Question from "./Question";
const ExternalPortal: React.FC<any> = (props) => {
const [href, setHref] = useState("Loading...");

const ref = useScrollOnPreviousURLMatch<HTMLLIElement>(href);

const addExternalPortal = useStore.getState().addExternalPortal;

const { data, loading } = useQuery(
Expand Down Expand Up @@ -84,7 +87,7 @@ const ExternalPortal: React.FC<any> = (props) => {
return (
<>
<Hanger hidden={isDragging} before={props.id} parent={parent} />
<li className={classNames("card", "portal", { isDragging })}>
<li className={classNames("card", "portal", { isDragging })} ref={ref}>
<Link href={`/${href}`} prefetch={false} ref={drag}>
<span>{href}</span>
</Link>
Expand Down Expand Up @@ -128,10 +131,12 @@ const InternalPortal: React.FC<any> = (props) => {

const Icon = ICONS[ComponentType.InternalPortal];

const ref = useScrollOnPreviousURLMatch<HTMLLIElement>(props.id);

return (
<>
<Hanger hidden={isDragging} before={props.id} parent={parent} />
<li className={classNames("card", "portal", { isDragging })}>
<li className={classNames("card", "portal", { isDragging })} ref={ref}>
<Link
href={href}
prefetch={false}
Expand Down
34 changes: 28 additions & 6 deletions editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { OT } from "@planx/graph/types";
import axios from "axios";
import { client } from "lib/graphql";
import navigation from "lib/navigation";
import debounce from "lodash/debounce";
import isEmpty from "lodash/isEmpty";
import omitBy from "lodash/omitBy";
Expand Down Expand Up @@ -55,6 +56,9 @@ export interface EditorUIStore {
toggleShowImages: () => void;
showDataFields: boolean;
toggleShowDataFields: () => void;
previousURL?: string;
currentURL: string;
initURLTracking: () => void;
}

export const editorUIStore: StateCreator<
Expand Down Expand Up @@ -87,6 +91,22 @@ export const editorUIStore: StateCreator<
showDataFields: false,

toggleShowDataFields: () => set({ showDataFields: !get().showDataFields }),

previousURL: undefined,

currentURL: window.location.pathname,

initURLTracking: () => {
navigation.subscribe((route) => {
const { currentURL } = get();
if (route.url.pathname === currentURL) return;

set((state) => ({
previousURL: state.currentURL,
currentURL: route.url.pathname,
}));
});
},
}),
{
name: "editorUIStore",
Expand Down Expand Up @@ -114,8 +134,8 @@ export interface FlowSummary {
actor: {
firstName: string;
lastName: string;
}
}[]
};
}[];
}

export interface EditorStore extends Store.Store {
Expand All @@ -127,7 +147,7 @@ export interface EditorStore extends Store.Store {
createFlow: (
teamId: number,
newSlug: string,
newName: string
newName: string,
) => Promise<string>;
deleteFlow: (teamId: number, flowSlug: string) => Promise<object>;
validateAndDiffFlow: (flowId: string) => Promise<any>;
Expand All @@ -142,12 +162,12 @@ export interface EditorStore extends Store.Store {
id: NodeId,
parent?: NodeId,
toBefore?: NodeId,
toParent?: NodeId
toParent?: NodeId,
) => void;
pasteNode: (toParent: NodeId, toBefore: NodeId) => void;
publishFlow: (
flowId: string,
summary?: string
summary?: string,
) => Promise<PublishFlowResponse>;
removeNode: (id: NodeId, parent: NodeId) => void;
updateNode: (node: any, relationships?: any) => void;
Expand Down Expand Up @@ -344,7 +364,9 @@ export const editorStore: StateCreator<

getFlows: async (teamId) => {
client.cache.reset();
const { data: { flows } } = await client.query<{ flows: FlowSummary[] }>({
const {
data: { flows },
} = await client.query<{ flows: FlowSummary[] }>({
query: gql`
query GetFlows($teamId: Int!) {
flows(where: { team: { id: { _eq: $teamId } } }) {
Expand Down
29 changes: 17 additions & 12 deletions editor.planx.uk/src/pages/layout/AuthenticatedLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { containerClasses } from "@mui/material/Container";
import { styled } from "@mui/material/styles";
import EditorNavMenu from "components/EditorNavMenu";
import RouteLoadingIndicator from "components/RouteLoadingIndicator";
import { useStore } from "pages/FlowEditor/lib/store";
import React, { PropsWithChildren } from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
Expand Down Expand Up @@ -33,17 +34,21 @@ const DashboardContainer = styled(Box)(({ theme }) => ({
},
}));

const Layout: React.FC<PropsWithChildren> = ({ children }) => (
<>
<RouteLoadingIndicator />
<Header />
<DashboardWrap>
<EditorNavMenu />
<DashboardContainer>
<DndProvider backend={HTML5Backend}>{children}</DndProvider>
</DashboardContainer>
</DashboardWrap>
</>
);
const Layout: React.FC<PropsWithChildren> = ({ children }) => {
useStore((state) => state.initURLTracking());

return (
<>
<RouteLoadingIndicator />
<Header />
<DashboardWrap>
<EditorNavMenu />
<DashboardContainer>
<DndProvider backend={HTML5Backend}>{children}</DndProvider>
</DashboardContainer>
</DashboardWrap>
</>
);
};

export default Layout;

0 comments on commit be24a07

Please sign in to comment.