Skip to content

Commit

Permalink
feat: Use zustand middleware to persist to local storage (#3767)
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr authored Oct 7, 2024
1 parent da15b40 commit 5963fd5
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 131 deletions.
232 changes: 114 additions & 118 deletions editor.planx.uk/src/pages/FlowEditor/components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import OpenInNewIcon from "@mui/icons-material/OpenInNew";
import OpenInNewOffIcon from "@mui/icons-material/OpenInNewOff";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Collapse from "@mui/material/Collapse";
import Container from "@mui/material/Container";
import Link from "@mui/material/Link";
import { styled } from "@mui/material/styles";
Expand All @@ -29,25 +30,18 @@ type SidebarTabs = "PreviewBrowser" | "History" | "Search" | "Console";
const SIDEBAR_WIDTH = "500px";
const SIDEBAR_WIDTH_MINIMISED = "20px";

const Root = styled(Box)<{ isMinimised: boolean }>(
({ theme, isMinimised }) => ({
position: "relative",
top: "0",
right: "0",
bottom: "0",
width: isMinimised ? SIDEBAR_WIDTH_MINIMISED : SIDEBAR_WIDTH,
display: "flex",
flexShrink: 0,
flexDirection: "column",
borderLeft: `1px solid ${theme.palette.border.main}`,
background: theme.palette.background.paper,
zIndex: 1,
transition: "width 200ms ease-in-out",
"& iframe": {
flex: 1,
},
}),
);
const Root = styled(Box)(({ theme }) => ({
position: "relative",
top: "0",
right: "0",
bottom: "0",
display: "flex",
flexShrink: 0,
flexDirection: "column",
borderLeft: `1px solid ${theme.palette.border.main}`,
background: theme.palette.background.paper,
zIndex: 1,
}));

const SidebarContainer = styled(Box)(() => ({
overflow: "auto",
Expand All @@ -62,7 +56,7 @@ const SidebarWrapper = styled(Box)(() => ({
flexDirection: "column",
flexShrink: 0,
flexGrow: 1,
maxHeight: "100%",
height: "100%",
}));

const StyledToggleButton = styled(ToggleButton)(({ theme }) => ({
Expand Down Expand Up @@ -132,16 +126,14 @@ const TabList = styled(Box)(({ theme }) => ({
}));

const Sidebar: React.FC = React.memo(() => {
const [resetPreview, isFlowPublished] = useStore((state) => [
const [resetPreview, isFlowPublished, toggleSidebar, showSidebar] = useStore((state) => [
state.resetPreview,
state.isFlowPublished,
state.toggleSidebar,
state.showSidebar,
]);

const [activeTab, setActiveTab] = useState<SidebarTabs>("PreviewBrowser");
const [isSidebarMinimised, setIsSidebarMinimised] = useState<boolean>(() => {
const savedState = localStorage.getItem("isSidebarMinimised");
return savedState === "true";
});

const handleChange = (
_event: React.SyntheticEvent,
Expand All @@ -150,14 +142,6 @@ const Sidebar: React.FC = React.memo(() => {
setActiveTab(newValue);
};

const togglePreview = () => {
setIsSidebarMinimised((prev) => {
const newState = !prev;
localStorage.setItem("isSidebarMinimised", JSON.stringify(newState));
return newState;
});
};

const baseUrl = `${window.location.origin}${rootFlowPath(false)}`;

const urls = {
Expand All @@ -167,102 +151,114 @@ const Sidebar: React.FC = React.memo(() => {
};

return (
<Root isMinimised={isSidebarMinimised}>
<SidebarWrapper>
<StyledToggleButton onClick={togglePreview} value="toggleSidebar">
{isSidebarMinimised ? <ChevronLeftIcon /> : <ChevronRightIcon />}
</StyledToggleButton>
<Header>
<Box width="100%" display="flex">
<input type="text" disabled value={urls.preview} />

<Permission.IsPlatformAdmin>
<Tooltip arrow title="Open draft service">
<Link
href={urls.draft}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<OpenInNewOffIcon />
</Link>
</Tooltip>
</Permission.IsPlatformAdmin>
<Root>
<Collapse
in={showSidebar}
orientation="horizontal"
collapsedSize={SIDEBAR_WIDTH_MINIMISED}
sx={{ height: "100%" }}
easing={"ease-in-out"}
timeout={200}
>
<SidebarWrapper>
<StyledToggleButton onClick={toggleSidebar} value="toggleSidebar">
{showSidebar
? <ChevronRightIcon />
: <ChevronLeftIcon />
}
</StyledToggleButton>
<Header>
<Box width="100%" display="flex">
<input type="text" disabled value={urls.preview} />

<Tooltip arrow title="Open preview of changes to publish">
<Link
href={urls.preview}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<OpenInNewIcon />
</Link>
</Tooltip>
<Permission.IsPlatformAdmin>
<Tooltip arrow title="Open draft service">
<Link
href={urls.draft}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<OpenInNewOffIcon />
</Link>
</Tooltip>
</Permission.IsPlatformAdmin>

{isFlowPublished ? (
<Tooltip arrow title="Open published service">
<Tooltip arrow title="Open preview of changes to publish">
<Link
href={urls.analytics}
href={urls.preview}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<LanguageIcon />
<OpenInNewIcon />
</Link>
</Tooltip>
) : (
<Tooltip arrow title="Flow not yet published">
<Box>
<Link component={"button"} disabled aria-disabled={true}>

{isFlowPublished ? (
<Tooltip arrow title="Open published service">
<Link
href={urls.analytics}
target="_blank"
rel="noopener noreferrer"
color="inherit"
>
<LanguageIcon />
</Link>
</Box>
</Tooltip>
)}
</Box>
<PublishFlowButton previewURL={urls.preview} />
</Header>
<TabList>
<Tabs onChange={handleChange} value={activeTab} aria-label="">
<StyledTab value="PreviewBrowser" label="Preview" />
<StyledTab value="History" label="History" />
<StyledTab value="Search" label="Search" />
<StyledTab value="Console" label="Console" />
</Tabs>
</TabList>
{activeTab === "PreviewBrowser" && (
<SidebarContainer>
<ResetToggle
variant="link"
onClick={() => {
resetPreview();
}}
>
<Reset fontSize="small" />
Restart
</ResetToggle>
<Questions previewEnvironment="editor" />
</SidebarContainer>
)}
{activeTab === "History" && (
<SidebarContainer py={3}>
<Container>
<EditHistory />
</Container>
</SidebarContainer>
)}
{activeTab === "Search" && (
<SidebarContainer>
<Search />
</SidebarContainer>
)}
{activeTab === "Console" && (
<SidebarContainer>
<DebugConsole />
</SidebarContainer>
)}
</SidebarWrapper>
</Tooltip>
) : (
<Tooltip arrow title="Flow not yet published">
<Box>
<Link component={"button"} disabled aria-disabled={true}>
<LanguageIcon />
</Link>
</Box>
</Tooltip>
)}
</Box>
<PublishFlowButton previewURL={urls.preview} />
</Header>
<TabList>
<Tabs onChange={handleChange} value={activeTab} aria-label="">
<StyledTab value="PreviewBrowser" label="Preview" />
<StyledTab value="History" label="History" />
<StyledTab value="Search" label="Search" />
<StyledTab value="Console" label="Console" />
</Tabs>
</TabList>
{activeTab === "PreviewBrowser" && (
<SidebarContainer>
<ResetToggle
variant="link"
onClick={() => {
resetPreview();
}}
>
<Reset fontSize="small" />
Restart
</ResetToggle>
<Questions previewEnvironment="editor" />
</SidebarContainer>
)}
{activeTab === "History" && (
<SidebarContainer py={3}>
<Container>
<EditHistory />
</Container>
</SidebarContainer>
)}
{activeTab === "Search" && (
<SidebarContainer>
<Search />
</SidebarContainer>
)}
{activeTab === "Console" && (
<SidebarContainer>
<DebugConsole />
</SidebarContainer>
)}
</SidebarWrapper>
</Collapse>
</Root>
);
});
Expand Down
3 changes: 1 addition & 2 deletions editor.planx.uk/src/pages/FlowEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const FlowEditor = () => {

const scrollContainerRef = useRef<HTMLDivElement>(null);
useScrollControlsAndRememberPosition(scrollContainerRef);
const showSidebar = useStore((state) => state.showSidebar);

const isTestEnvBannerVisible = useStore(
(state) => state.isTestEnvBannerVisible,
Expand All @@ -52,7 +51,7 @@ const FlowEditor = () => {
<Flow flow={flow} breadcrumbs={breadcrumbs} />
</Box>
</Box>
{showSidebar && <Sidebar />}
<Sidebar />
</EditorContainer>
);
};
Expand Down
29 changes: 18 additions & 11 deletions editor.planx.uk/src/pages/FlowEditor/lib/store/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { customAlphabet } from "nanoid-good";
import en from "nanoid-good/locale/en";
import { type } from "ot-json0";
import type { StateCreator } from "zustand";
import { persist } from 'zustand/middleware'

import { FlowLayout } from "../../components/Flow";
import { connectToDB, getConnection } from "./../sharedb";
Expand All @@ -45,29 +46,35 @@ const send = (ops: Array<any>) => {
export interface EditorUIStore {
flowLayout: FlowLayout;
showSidebar: boolean;
togglePreview: () => void;
toggleSidebar: () => void;
isTestEnvBannerVisible: boolean;
hideTestEnvBanner: () => void;
}

export const editorUIStore: StateCreator<
SharedStore & EditorUIStore,
[],
[],
[["zustand/persist", unknown]],
EditorUIStore
> = (set, get) => ({
flowLayout: FlowLayout.TOP_DOWN,
> = persist(
(set, get) => ({
flowLayout: FlowLayout.TOP_DOWN,

showSidebar: true,
showSidebar: true,

togglePreview: () => {
set({ showSidebar: !get().showSidebar });
},
toggleSidebar: () => {
set({ showSidebar: !get().showSidebar });
},

isTestEnvBannerVisible: !window.location.href.includes(".uk"),
isTestEnvBannerVisible: !window.location.href.includes(".uk"),

hideTestEnvBanner: () => set({ isTestEnvBannerVisible: false }),
});
hideTestEnvBanner: () => set({ isTestEnvBannerVisible: false }),
}),
{
name: "editorUIStore",
partialize: (state) => ({ showSidebar: state.showSidebar }),
}
);

interface PublishFlowResponse {
alteredNodes: Store.Node[];
Expand Down

0 comments on commit 5963fd5

Please sign in to comment.