♻️ Lift right side bar state to the URL

This commit is contained in:
Baptiste Arnaud 2025-02-19 10:09:04 +01:00
parent fb3eda4e87
commit 07e1eb41c3
No known key found for this signature in database
10 changed files with 62 additions and 63 deletions

View File

@ -8,6 +8,7 @@ import {
} from "@/components/icons";
import { ParentModalProvider } from "@/features/graph/providers/ParentModalProvider";
import { parseDefaultPublicId } from "@/features/publish/helpers/parseDefaultPublicId";
import { useRightPanel } from "@/hooks/useRightPanel";
import {
HStack,
IconButton,
@ -21,7 +22,6 @@ import {
} from "@chakra-ui/react";
import { useTranslate } from "@tolgee/react";
import React, { useState } from "react";
import { RightPanel, useEditor } from "../providers/EditorProvider";
import { useTypebot } from "../providers/TypebotProvider";
import { EditorSettingsModal } from "./EditorSettingsModal";
@ -30,7 +30,7 @@ export const BoardMenuButton = (props: StackProps) => {
const [isDownloading, setIsDownloading] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const { t } = useTranslate();
const { setRightPanel } = useEditor();
const [, setRightPanel] = useRightPanel();
const downloadFlow = () => {
assert(typebot);
@ -60,7 +60,7 @@ export const BoardMenuButton = (props: StackProps) => {
size="sm"
shadow="md"
bgColor={useColorModeValue("white", undefined)}
onClick={() => setRightPanel(RightPanel.VARIABLES)}
onClick={() => setRightPanel("variables")}
/>
<Menu>
<MenuButton

View File

@ -6,12 +6,9 @@ import { VideoOnboardingFloatingWindow } from "@/features/onboarding/components/
import { PreviewDrawer } from "@/features/preview/components/PreviewDrawer";
import { VariablesDrawer } from "@/features/preview/components/VariablesDrawer";
import { useWorkspace } from "@/features/workspace/WorkspaceProvider";
import { useRightPanel } from "@/hooks/useRightPanel";
import { Flex, Spinner, useColorModeValue } from "@chakra-ui/react";
import {
EditorProvider,
RightPanel as RightPanelEnum,
useEditor,
} from "../providers/EditorProvider";
import { EditorProvider } from "../providers/EditorProvider";
import { useTypebot } from "../providers/TypebotProvider";
import { BlocksSideBar } from "./BlocksSideBar";
import { BoardMenuButton } from "./BoardMenuButton";
@ -77,14 +74,14 @@ export const EditorPage = () => {
};
const RightPanel = () => {
const { rightPanel, setRightPanel } = useEditor();
const [rightPanel, setRightPanel] = useRightPanel();
switch (rightPanel) {
case RightPanelEnum.PREVIEW:
case "preview":
return <PreviewDrawer />;
case RightPanelEnum.VARIABLES:
return <VariablesDrawer onClose={() => setRightPanel(undefined)} />;
case undefined:
case "variables":
return <VariablesDrawer onClose={() => setRightPanel(null)} />;
case null:
return null;
}
};

View File

@ -13,6 +13,7 @@ import { ShareTypebotButton } from "@/features/share/components/ShareTypebotButt
import { useWorkspace } from "@/features/workspace/WorkspaceProvider";
import { isCloudProdInstance } from "@/helpers/isCloudProdInstance";
import { useKeyboardShortcuts } from "@/hooks/useKeyboardShortcuts";
import { useRightPanel } from "@/hooks/useRightPanel";
import {
Button,
Flex,
@ -34,7 +35,7 @@ import { useRouter } from "next/router";
import React, { useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import { headerHeight } from "../constants";
import { RightPanel, useEditor } from "../providers/EditorProvider";
import { useEditor } from "../providers/EditorProvider";
import { useTypebot } from "../providers/TypebotProvider";
import { EditableTypebotName } from "./EditableTypebotName";
import { GuestTypebotHeader } from "./UnauthenticatedTypebotHeader";
@ -42,7 +43,6 @@ import { GuestTypebotHeader } from "./UnauthenticatedTypebotHeader";
export const TypebotHeader = () => {
const { typebot, publishedTypebot, currentUserMode } = useTypebot();
const { workspace } = useWorkspace();
const { isOpen, onOpen } = useDisclosure();
const headerBgColor = useColorModeValue("white", "gray.950");
@ -254,12 +254,13 @@ const RightElements = ({
const router = useRouter();
const { t } = useTranslate();
const { typebot, currentUserMode, save, isSavingLoading } = useTypebot();
const { setRightPanel, rightPanel, setStartPreviewFrom } = useEditor();
const { setStartPreviewFrom } = useEditor();
const [rightPanel, setRightPanel] = useRightPanel();
const handlePreviewClick = async () => {
setStartPreviewFrom(undefined);
await save();
setRightPanel(RightPanel.PREVIEW);
setRightPanel("preview");
};
return (
@ -272,21 +273,20 @@ const RightElements = ({
<Flex pos="relative">
<ShareTypebotButton isLoading={isNotDefined(typebot)} />
</Flex>
{router.pathname.includes("/edit") &&
rightPanel !== RightPanel.PREVIEW && (
<Button
colorScheme="gray"
onClick={handlePreviewClick}
isLoading={isNotDefined(typebot) || isSavingLoading}
leftIcon={<PlayIcon />}
size="sm"
iconSpacing={{ base: 0, xl: 2 }}
>
<chakra.span display={{ base: "none", xl: "inline" }}>
{t("editor.header.previewButton.label")}
</chakra.span>
</Button>
)}
{router.pathname.includes("/edit") && rightPanel !== "preview" && (
<Button
colorScheme="gray"
onClick={handlePreviewClick}
isLoading={isNotDefined(typebot) || isSavingLoading}
leftIcon={<PlayIcon />}
size="sm"
iconSpacing={{ base: 0, xl: 2 }}
>
<chakra.span display={{ base: "none", xl: "inline" }}>
{t("editor.header.previewButton.label")}
</chakra.span>
</Button>
)}
{currentUserMode === "guest" && (
<Button
as={Link}

View File

@ -2,6 +2,7 @@ import { EmojiOrImageIcon } from "@/components/EmojiOrImageIcon";
import { TypebotLogo } from "@/components/TypebotLogo";
import { CopyIcon, PlayIcon } from "@/components/icons";
import { useUser } from "@/features/user/hooks/useUser";
import { useRightPanel } from "@/hooks/useRightPanel";
import {
Button,
Divider,
@ -16,7 +17,7 @@ import Link from "next/link";
import { useRouter } from "next/router";
import React from "react";
import { headerHeight } from "../constants";
import { RightPanel, useEditor } from "../providers/EditorProvider";
import { useEditor } from "../providers/EditorProvider";
import { useTypebot } from "../providers/TypebotProvider";
export const GuestTypebotHeader = () => {
@ -24,12 +25,13 @@ export const GuestTypebotHeader = () => {
const router = useRouter();
const { user } = useUser();
const { typebot, save } = useTypebot();
const { setRightPanel, rightPanel, setStartPreviewFrom } = useEditor();
const { setStartPreviewFrom } = useEditor();
const [rightPanel, setRightPanel] = useRightPanel();
const handlePreviewClick = async () => {
setStartPreviewFrom(undefined);
save().then();
setRightPanel(RightPanel.PREVIEW);
setRightPanel("preview");
};
return (

View File

@ -7,14 +7,7 @@ import {
useState,
} from "react";
export enum RightPanel {
PREVIEW = 0,
VARIABLES = 1,
}
const editorContext = createContext<{
rightPanel?: RightPanel;
setRightPanel: Dispatch<SetStateAction<RightPanel | undefined>>;
startPreviewFrom:
| {
type: "group" | "event";
@ -34,7 +27,6 @@ const editorContext = createContext<{
}>({});
export const EditorProvider = ({ children }: { children: ReactNode }) => {
const [rightPanel, setRightPanel] = useState<RightPanel>();
const [startPreviewFrom, setStartPreviewFrom] = useState<
| {
type: "group" | "event";
@ -46,8 +38,6 @@ export const EditorProvider = ({ children }: { children: ReactNode }) => {
return (
<editorContext.Provider
value={{
rightPanel,
setRightPanel,
startPreviewFrom,
setStartPreviewFrom,
}}

View File

@ -1,8 +1,5 @@
import { ContextMenu } from "@/components/ContextMenu";
import {
RightPanel,
useEditor,
} from "@/features/editor/providers/EditorProvider";
import { useEditor } from "@/features/editor/providers/EditorProvider";
import { useTypebot } from "@/features/editor/providers/TypebotProvider";
import { SettingsModal } from "@/features/graph/components/nodes/block/SettingsModal";
import {
@ -14,6 +11,7 @@ import { useSelectionStore } from "@/features/graph/hooks/useSelectionStore";
import { useGraph } from "@/features/graph/providers/GraphProvider";
import { ParentModalProvider } from "@/features/graph/providers/ParentModalProvider";
import { setMultipleRefs } from "@/helpers/setMultipleRefs";
import { useRightPanel } from "@/hooks/useRightPanel";
import {
Popover,
PopoverTrigger,
@ -43,8 +41,9 @@ export const EventNode = ({ event, eventIndex }: Props) => {
const elementBgColor = useColorModeValue("white", "gray.950");
const previewingBorderColor = useColorModeValue("orange.400", "orange.300");
const { previewingEdge, isReadOnly, graphPosition } = useGraph();
const { updateEvent, deleteEvent, updateEventsCoordinates } = useTypebot();
const { setRightPanel, setStartPreviewFrom } = useEditor();
const { updateEvent, updateEventsCoordinates } = useTypebot();
const { setStartPreviewFrom } = useEditor();
const [, setRightPanel] = useRightPanel();
const [isMouseDown, setIsMouseDown] = useState(false);
const focusedElements = useSelectionStore(
@ -88,7 +87,7 @@ export const EventNode = ({ event, eventIndex }: Props) => {
const startPreviewAtThisEvent = () => {
setStartPreviewFrom({ type: "event", id: event.id });
setRightPanel(RightPanel.PREVIEW);
setRightPanel("preview");
};
const handleOnNodeChange = (

View File

@ -1,14 +1,12 @@
import { ContextMenu } from "@/components/ContextMenu";
import {
RightPanel,
useEditor,
} from "@/features/editor/providers/EditorProvider";
import { useEditor } from "@/features/editor/providers/EditorProvider";
import { useTypebot } from "@/features/editor/providers/TypebotProvider";
import { groupWidth } from "@/features/graph/constants";
import { useSelectionStore } from "@/features/graph/hooks/useSelectionStore";
import { useBlockDnd } from "@/features/graph/providers/GraphDndProvider";
import { useGraph } from "@/features/graph/providers/GraphProvider";
import { setMultipleRefs } from "@/helpers/setMultipleRefs";
import { useRightPanel } from "@/hooks/useRightPanel";
import {
Editable,
EditableInput,
@ -25,7 +23,6 @@ import { useShallow } from "zustand/react/shallow";
import { BlockNodesList } from "../block/BlockNodesList";
import { GroupFocusToolbar } from "./GroupFocusToolbar";
import { GroupNodeContextMenu } from "./GroupNodeContextMenu";
type Props = {
group: GroupV6;
groupIndex: number;
@ -45,7 +42,8 @@ export const GroupNode = ({ group, groupIndex }: Props) => {
} = useGraph();
const { typebot, updateGroup, updateGroupsCoordinates } = useTypebot();
const { setMouseOverGroup, mouseOverGroup } = useBlockDnd();
const { setRightPanel, setStartPreviewFrom } = useEditor();
const { setStartPreviewFrom } = useEditor();
const [, setRightPanel] = useRightPanel();
const [isMouseDown, setIsMouseDown] = useState(false);
const [isConnecting, setIsConnecting] = useState(false);
@ -111,7 +109,7 @@ export const GroupNode = ({ group, groupIndex }: Props) => {
const startPreviewAtThisGroup = () => {
setStartPreviewFrom({ type: "group", id: group.id });
setRightPanel(RightPanel.PREVIEW);
setRightPanel("preview");
};
useDrag(

View File

@ -1,4 +1,5 @@
import { useGraph } from "@/features/graph/providers/GraphProvider";
import { useRightPanel } from "@/hooks/useRightPanel";
import {
Button,
CloseButton,
@ -12,7 +13,6 @@ import { useTranslate } from "@tolgee/react";
import { useDrag } from "@use-gesture/react";
import React, { useState } from "react";
import { headerHeight } from "../../editor/constants";
import { useEditor } from "../../editor/providers/EditorProvider";
import { useTypebot } from "../../editor/providers/TypebotProvider";
import { runtimes } from "../data";
import { PreviewDrawerBody } from "./PreviewDrawerBody";
@ -32,7 +32,6 @@ const getDefaultRuntime = (typebotId?: string) => {
export const PreviewDrawer = () => {
const { typebot, save, isSavingLoading } = useTypebot();
const { t } = useTranslate();
const { setRightPanel } = useEditor();
const { setPreviewingBlock } = useGraph();
const [width, setWidth] = useState(500);
const [isResizeHandleVisible, setIsResizeHandleVisible] = useState(false);
@ -40,6 +39,7 @@ export const PreviewDrawer = () => {
const [selectedRuntime, setSelectedRuntime] = useState<
(typeof runtimes)[number]
>(getDefaultRuntime(typebot?.id));
const [, setRightPanel] = useRightPanel();
const handleRestartClick = async () => {
await save();
@ -48,7 +48,7 @@ export const PreviewDrawer = () => {
const handleCloseClick = () => {
setPreviewingBlock(undefined);
setRightPanel(undefined);
setRightPanel(null);
};
const useResizeHandleDrag = useDrag(

View File

@ -0,0 +1,9 @@
import { parseAsStringLiteral, useQueryState } from "nuqs";
const rightPanels = ["preview", "variables"] as const;
export const useRightPanel = () =>
useQueryState<(typeof rightPanels)[number]>(
"rightPanel",
parseAsStringLiteral(rightPanels),
);

View File

@ -2,7 +2,11 @@ import Router from "next/router";
import NProgress from "nprogress";
import { useEffect } from "react";
const progressStarted = () => NProgress.start();
const progressStarted = (url: string) => {
if (Router.asPath.split("?")[0] === url.split("?")[0]) return;
NProgress.start();
};
const progressComplete = () => NProgress.done();
export const useRouterProgressBar = () =>