From 9ad75bd93759815fe01c00fabe09b3d1cad28136 Mon Sep 17 00:00:00 2001
From: Robert Knight <95928279+microbit-robert@users.noreply.github.com>
Date: Tue, 3 Dec 2024 12:16:03 +0000
Subject: [PATCH] Pull up dialogs to prevent odd behaviours (#551)
---
src/components/{ => ActionBar}/ActionBar.tsx | 0
.../ActionBar/ActionBarItemsRight.tsx | 119 +++++++++++++++++
src/components/DefaultPageLayout.tsx | 50 ++------
src/components/HelpMenu.tsx | 38 +++---
src/components/HelpMenuItems.tsx | 120 +++++++-----------
src/components/LanguageMenuItem.tsx | 27 +---
src/components/SettingsMenu.tsx | 13 +-
src/components/SettingsMenuItem.tsx | 30 ++---
8 files changed, 224 insertions(+), 173 deletions(-)
rename src/components/{ => ActionBar}/ActionBar.tsx (100%)
create mode 100644 src/components/ActionBar/ActionBarItemsRight.tsx
diff --git a/src/components/ActionBar.tsx b/src/components/ActionBar/ActionBar.tsx
similarity index 100%
rename from src/components/ActionBar.tsx
rename to src/components/ActionBar/ActionBar.tsx
diff --git a/src/components/ActionBar/ActionBarItemsRight.tsx b/src/components/ActionBar/ActionBarItemsRight.tsx
new file mode 100644
index 000000000..53b66e0a6
--- /dev/null
+++ b/src/components/ActionBar/ActionBarItemsRight.tsx
@@ -0,0 +1,119 @@
+import { HStack, MenuDivider, useDisclosure } from "@chakra-ui/react";
+import { ReactNode, useMemo } from "react";
+import { useIntl } from "react-intl";
+import { useLocation } from "react-router";
+import { useStore } from "../../store";
+import AboutDialog from "../AboutDialog";
+import ConnectFirstDialog from "../ConnectFirstDialog";
+import FeedbackForm from "../FeedbackForm";
+import HelpMenu from "../HelpMenu";
+import HelpMenuItems, { tourMap } from "../HelpMenuItems";
+import { LanguageDialog } from "../LanguageDialog";
+import LanguageMenuItem from "../LanguageMenuItem";
+import { SettingsDialog } from "../SettingsDialog";
+import SettingsMenu from "../SettingsMenu";
+import SettingsMenuItem from "../SettingsMenuItem";
+import ToolbarMenu from "../ToolbarMenu";
+
+interface ItemsRightProps {
+ menuItems?: ReactNode;
+ toolbarItems?: ReactNode;
+}
+
+const ItemsRight = ({ menuItems, toolbarItems }: ItemsRightProps) => {
+ const intl = useIntl();
+ const languageDisclosure = useDisclosure();
+ const settingsDisclosure = useDisclosure();
+ const aboutDialogDisclosure = useDisclosure();
+ const feedbackDisclosure = useDisclosure();
+ const connectFirstDisclosure = useDisclosure();
+ const setPostConnectTourTrigger = useStore(
+ (s) => s.setPostConnectTourTrigger
+ );
+ const tourTriggerName = tourMap[useLocation().pathname];
+ const tourTrigger = useMemo(() => {
+ switch (tourTriggerName) {
+ case "TrainModel": {
+ return {
+ name: tourTriggerName,
+ delayedUntilConnection: true,
+ };
+ }
+ case "Connect": {
+ return { name: tourTriggerName };
+ }
+ default: {
+ return undefined;
+ }
+ }
+ }, [tourTriggerName]);
+ return (
+ <>
+
+
+ setPostConnectTourTrigger(tourTrigger)}
+ explanationTextId="connect-to-tour-body"
+ options={{ postConnectTourTrigger: tourTrigger }}
+ />
+
+
+
+ {toolbarItems}
+
+
+
+
+ {menuItems}
+
+
+
+ {/* Toolbar items when sm window size. */}
+
+ {menuItems}
+
+
+
+
+
+ >
+ );
+};
+
+export default ItemsRight;
diff --git a/src/components/DefaultPageLayout.tsx b/src/components/DefaultPageLayout.tsx
index 5553d0d09..b0db0208a 100644
--- a/src/components/DefaultPageLayout.tsx
+++ b/src/components/DefaultPageLayout.tsx
@@ -2,7 +2,6 @@ import {
Button,
Flex,
Heading,
- HStack,
Icon,
IconButton,
MenuDivider,
@@ -28,21 +27,16 @@ import {
import Tour from "../pages/Tour";
import { useStore } from "../store";
import { createHomePageUrl } from "../urls";
-import ActionBar from "./ActionBar";
+import ActionBar from "./ActionBar/ActionBar";
import AppLogo from "./AppLogo";
import ConnectionDialogs from "./ConnectionFlowDialogs";
-import HelpMenu from "./HelpMenu";
-import LanguageMenuItem from "./LanguageMenuItem";
+import ImportErrorDialog from "./ImportErrorDialog";
+import MakeCodeLoadErrorDialog from "./MakeCodeLoadErrorDialog";
+import NotCreateAiHexImportDialog from "./NotCreateAiHexImportDialog";
import PreReleaseNotice from "./PreReleaseNotice";
import ProjectDropTarget from "./ProjectDropTarget";
import SaveDialogs from "./SaveDialogs";
-import SettingsMenu from "./SettingsMenu";
-import ToolbarMenu from "./ToolbarMenu";
-import HelpMenuItems from "./HelpMenuItems";
-import ImportErrorDialog from "./ImportErrorDialog";
-import NotCreateAiHexImportDialog from "./NotCreateAiHexImportDialog";
-import MakeCodeLoadErrorDialog from "./MakeCodeLoadErrorDialog";
-import SettingsMenuItem from "./SettingsMenuItem";
+import ItemsRight from "./ActionBar/ActionBarItemsRight";
interface DefaultPageLayoutProps {
titleId?: string;
@@ -151,36 +145,10 @@ const DefaultPageLayout = ({
}
itemsLeftProps={{ width: 0 }}
itemsRight={
- <>
-
- {toolbarItemsRight}
-
-
-
-
- {menuItems}
-
-
-
- {/* Toolbar items when sm window size. */}
-
- {menuItems}
-
-
-
-
-
- >
+
}
/>
{flags.preReleaseNotice && }
diff --git a/src/components/HelpMenu.tsx b/src/components/HelpMenu.tsx
index f135f4901..8ea16e813 100644
--- a/src/components/HelpMenu.tsx
+++ b/src/components/HelpMenu.tsx
@@ -6,38 +6,35 @@ import {
MenuButton,
MenuList,
Portal,
- useDisclosure,
} from "@chakra-ui/react";
import { useRef } from "react";
import { RiQuestionLine } from "react-icons/ri";
import { useIntl } from "react-intl";
-import AboutDialog from "./AboutDialog";
-import FeedbackForm from "./FeedbackForm";
import HelpMenuItems from "./HelpMenuItems";
+import { TourTrigger } from "../model";
-interface HelpMenuProps extends BoxProps {}
+interface HelpMenuProps extends BoxProps {
+ onAboutDialogOpen: () => void;
+ onConnectFirstDialogOpen: () => void;
+ onFeedbackOpen: () => void;
+ tourTrigger: TourTrigger | undefined;
+}
/**
* A help button that triggers a drop-down menu with actions.
*/
-const HelpMenu = ({ ...rest }: HelpMenuProps) => {
- const aboutDialogDisclosure = useDisclosure();
- const feedbackDisclosure = useDisclosure();
+const HelpMenu = ({
+ onAboutDialogOpen,
+ onConnectFirstDialogOpen,
+ onFeedbackOpen,
+ tourTrigger,
+ ...rest
+}: HelpMenuProps) => {
const intl = useIntl();
const menuButtonRef = useRef(null);
const containerRef = useRef(null);
return (
-
-
diff --git a/src/components/HelpMenuItems.tsx b/src/components/HelpMenuItems.tsx
index 086a7aeb7..ec4d4f65c 100644
--- a/src/components/HelpMenuItems.tsx
+++ b/src/components/HelpMenuItems.tsx
@@ -1,5 +1,4 @@
-import { MenuDivider, MenuItem, useDisclosure } from "@chakra-ui/react";
-import { useRef } from "react";
+import { MenuDivider, MenuItem } from "@chakra-ui/react";
import { MdOutlineCookie } from "react-icons/md";
import {
RiExternalLinkLine,
@@ -8,34 +7,29 @@ import {
RiInformationLine,
} from "react-icons/ri";
import { FormattedMessage } from "react-intl";
-import { useLocation } from "react-router";
import { useConnectionStage } from "../connection-stage-hooks";
import { useDeployment } from "../deployment";
+import { flags } from "../flags";
+import { TourTrigger } from "../model";
import { useStore } from "../store";
-import { createDataSamplesPageUrl, createTestingModelPageUrl } from "../urls";
import { userGuideUrl } from "../utils/external-links";
-import AboutDialog from "./AboutDialog";
-import ConnectFirstDialog from "./ConnectFirstDialog";
-import FeedbackForm from "./FeedbackForm";
-import { flags } from "../flags";
+import { createDataSamplesPageUrl, createTestingModelPageUrl } from "../urls";
-const HelpMenuItems = () => {
- const aboutDialogDisclosure = useDisclosure();
- const feedbackDisclosure = useDisclosure();
- const menuButtonRef = useRef(null);
+interface HelpMenuItemsProps {
+ onAboutDialogOpen: () => void;
+ onConnectFirstDialogOpen: () => void;
+ onFeedbackOpen: () => void;
+ tourTrigger: TourTrigger | undefined;
+}
+const HelpMenuItems = ({
+ onAboutDialogOpen,
+ onConnectFirstDialogOpen,
+ onFeedbackOpen,
+ tourTrigger,
+}: HelpMenuItemsProps) => {
const deployment = useDeployment();
return (
<>
-
-
{flags.websiteContent && (
)}
-
+
{deployment.supportLinks.main && (
<>
- }
- onClick={feedbackDisclosure.onOpen}
- >
+ } onClick={onFeedbackOpen}>
@@ -102,63 +96,47 @@ const HelpMenuItems = () => {
{(deployment.privacyPolicyLink ||
deployment.compliance.manageCookies ||
deployment.termsOfUseLink) && }
- }
- onClick={aboutDialogDisclosure.onOpen}
- >
+ } onClick={onAboutDialogOpen}>
>
);
};
-const tourMap = {
- [createDataSamplesPageUrl()]: "Connect" as const,
- [createTestingModelPageUrl()]: "TrainModel" as const,
- // No UI to retrigger MakeCode tour
-};
+interface TourMenuItemProps {
+ onConnectFirstDialogOpen: () => void;
+ tourTrigger: TourTrigger | undefined;
+}
-const TourMenuItem = () => {
- const tourTriggerName = tourMap[useLocation().pathname];
- const setPostConnectTourTrigger = useStore(
- (s) => s.setPostConnectTourTrigger
- );
+const TourMenuItem = ({
+ onConnectFirstDialogOpen,
+ tourTrigger,
+}: TourMenuItemProps) => {
const tourStart = useStore((s) => s.tourStart);
- const disclosure = useDisclosure();
const { isConnected } = useConnectionStage();
- if (tourTriggerName) {
- const tourTrigger =
- tourTriggerName === "TrainModel"
- ? {
- name: tourTriggerName,
- delayedUntilConnection: true,
- }
- : { name: tourTriggerName };
+ if (tourTrigger) {
return (
- <>
- setPostConnectTourTrigger(tourTrigger)}
- explanationTextId="connect-to-tour-body"
- options={{ postConnectTourTrigger: tourTrigger }}
- />
-
- >
+
);
}
return null;
};
+export const tourMap = {
+ [createDataSamplesPageUrl()]: "Connect" as const,
+ [createTestingModelPageUrl()]: "TrainModel" as const,
+ // No UI to retrigger MakeCode tour
+};
+
export default HelpMenuItems;
diff --git a/src/components/LanguageMenuItem.tsx b/src/components/LanguageMenuItem.tsx
index e56c3f58e..793be22a3 100644
--- a/src/components/LanguageMenuItem.tsx
+++ b/src/components/LanguageMenuItem.tsx
@@ -1,29 +1,16 @@
-import { Icon, MenuItem, useDisclosure } from "@chakra-ui/react";
-import { FormattedMessage } from "react-intl";
+import { Icon, MenuItem } from "@chakra-ui/react";
import { IoMdGlobe } from "react-icons/io";
-import { LanguageDialog } from "./LanguageDialog";
+import { FormattedMessage } from "react-intl";
interface LanguageMenuItemProps {
- finalFocusRef?: React.RefObject;
+ onOpen: () => void;
}
-const LanguageMenuItem = ({ finalFocusRef }: LanguageMenuItemProps) => {
- const languageDisclosure = useDisclosure();
-
+const LanguageMenuItem = ({ onOpen }: LanguageMenuItemProps) => {
return (
- <>
-
- }
- onClick={languageDisclosure.onOpen}
- >
-
-
- >
+ } onClick={onOpen}>
+
+
);
};
diff --git a/src/components/SettingsMenu.tsx b/src/components/SettingsMenu.tsx
index f7bf51ff2..dd1e221ce 100644
--- a/src/components/SettingsMenu.tsx
+++ b/src/components/SettingsMenu.tsx
@@ -12,10 +12,17 @@ import { useIntl } from "react-intl";
import LanguageMenuItem from "./LanguageMenuItem";
import SettingsMenuItem from "./SettingsMenuItem";
+interface SettingsMenuProps {
+ onLanguageDialogOpen: () => void;
+ onSettingsDialogOpen: () => void;
+}
/**
* A settings button that triggers a drop-down menu with actions.
*/
-const SettingsMenu = () => {
+const SettingsMenu = ({
+ onLanguageDialogOpen,
+ onSettingsDialogOpen,
+}: SettingsMenuProps) => {
const intl = useIntl();
const settingsMenuRef = useRef(null);
const containerRef = useRef(null);
@@ -40,8 +47,8 @@ const SettingsMenu = () => {
/>
-
-
+
+
diff --git a/src/components/SettingsMenuItem.tsx b/src/components/SettingsMenuItem.tsx
index eb3b8cb43..e96a0f23d 100644
--- a/src/components/SettingsMenuItem.tsx
+++ b/src/components/SettingsMenuItem.tsx
@@ -1,29 +1,19 @@
-import { Icon, MenuItem, useDisclosure } from "@chakra-ui/react";
-import { FormattedMessage } from "react-intl";
+import { Icon, MenuItem } from "@chakra-ui/react";
import { RiListSettingsLine } from "react-icons/ri";
-import { SettingsDialog } from "./SettingsDialog";
+import { FormattedMessage } from "react-intl";
interface SettingsMenuItemProps {
- finalFocusRef?: React.RefObject;
+ onOpen: () => void;
}
-const SettingsMenuItem = ({ finalFocusRef }: SettingsMenuItemProps) => {
- const { isOpen, onClose, onOpen } = useDisclosure();
-
+const SettingsMenuItem = ({ onOpen }: SettingsMenuItemProps) => {
return (
- <>
-
- }
- onClick={onOpen}
- >
-
-
- >
+ }
+ onClick={onOpen}
+ >
+
+
);
};