diff --git a/src/editor/components/Main.js b/src/editor/components/Main.js
index aafcdcf67..be497e3db 100644
--- a/src/editor/components/Main.js
+++ b/src/editor/components/Main.js
@@ -1,5 +1,5 @@
import { HelpButton, GeoPanel, ZoomButtons } from './components';
-import { Component } from 'react';
+import { useState, useEffect } from 'react';
import ComponentsSidebar from './components/Sidebar';
import Events from '../lib/Events';
import ModalTextures from './modals/ModalTextures';
@@ -17,64 +17,75 @@ import { PaymentModal } from './modals/PaymentModal';
import { SceneEditTitle } from './components/SceneEditTitle';
import { AddLayerPanel } from './components/AddLayerPanel';
import { IntroModal } from './modals/IntroModal';
-import posthog from 'posthog-js';
import { ToolbarWrapper } from './scenegraph/ToolbarWrapper.js';
+import useStore from '@/store';
THREE.ImageUtils.crossOrigin = '';
-const isStreetLoaded = window.location.hash.length;
-const isPaymentModalOpened = window.location.hash.includes('payment');
-
// Define the libraries array as a constant outside of the component
const GOOGLE_MAPS_LIBRARIES = ['places'];
-export default class Main extends Component {
- constructor(props) {
- super(props);
- this.state = {
- entity: null,
- inspectorEnabled: true,
- isModalTexturesOpen: false,
- isSignInModalOpened: false,
- isProfileModalOpened: false,
- isAddLayerPanelOpen: false,
- isGeoModalOpened: false,
- isIntroModalOpened: false,
- isScenesModalOpened: !isStreetLoaded,
- isPaymentModalOpened: isPaymentModalOpened,
- sceneEl: AFRAME.scenes[0],
- visible: {
- scenegraph: true,
- attributes: true
- }
- };
+export default function Main() {
+ const [state, setState] = useState({
+ entity: null,
+ isModalTexturesOpen: false,
+ sceneEl: AFRAME.scenes[0],
+ visible: {
+ scenegraph: true,
+ attributes: true
+ }
+ });
+
+ useEffect(() => {
+ const htmlEditorButton = document?.querySelector(
+ '.viewer-logo-start-editor-button'
+ );
+ htmlEditorButton && htmlEditorButton.remove();
+ handleStreetMixURL();
+ window.addEventListener('hashchange', () => handleStreetMixURL());
+ Events.on('opentexturesmodal', function (selectedTexture, textureOnClose) {
+ setState((prevState) => ({
+ ...prevState,
+ selectedTexture: selectedTexture,
+ isModalTexturesOpen: true,
+ textureOnClose: textureOnClose
+ }));
+ });
+ Events.on('entityselect', (entity) => {
+ setState((prevState) => ({
+ ...prevState,
+ entity: entity
+ }));
+ });
Events.on('togglesidebar', (event) => {
if (event.which === 'all') {
- if (this.state.visible.scenegraph || this.state.visible.attributes) {
- this.setState({
+ if (state.visible.scenegraph || state.visible.attributes) {
+ setState((prevState) => ({
+ ...prevState,
visible: {
scenegraph: false,
attributes: false
}
- });
+ }));
} else {
- this.setState({
+ setState((prevState) => ({
+ ...prevState,
visible: {
scenegraph: true,
attributes: true
}
- });
+ }));
}
} else if (event.which === 'attributes') {
- this.setState((prevState) => ({
+ setState((prevState) => ({
visible: {
...prevState.visible,
attributes: !prevState.visible.attributes
}
}));
} else if (event.which === 'scenegraph') {
- this.setState((prevState) => ({
+ setState((prevState) => ({
visible: {
...prevState.visible,
scenegraph: !prevState.visible.scenegraph
@@ -82,257 +93,86 @@ export default class Main extends Component {
}));
}
});
- }
+ }, []);
- handleStreetMixURL() {
+ const handleStreetMixURL = () => {
const isStreetMix = window.location.hash.includes('streetmix');
if (isStreetMix) {
- const shownIntro = localStorage.getItem('shownIntro');
- if (!shownIntro) {
- this.setState({ isIntroModalOpened: true });
- }
STREET.notify.warningMessage(
'Hit save if you want to save changes to the scene. Otherwise changes will be lost'
);
}
- }
-
- componentDidMount() {
- const htmlEditorButton = document?.querySelector(
- '.viewer-logo-start-editor-button'
- );
- htmlEditorButton && htmlEditorButton.remove();
-
- this.handleStreetMixURL();
- window.addEventListener('hashchange', () => this.handleStreetMixURL());
- Events.on(
- 'opentexturesmodal',
- function (selectedTexture, textureOnClose) {
- this.setState({
- selectedTexture: selectedTexture,
- isModalTexturesOpen: true,
- textureOnClose: textureOnClose
- });
- }.bind(this)
- );
- Events.on('entityselect', (entity) => {
- this.setState({ entity: entity });
- });
- Events.on('inspectortoggle', (enabled) => {
- posthog.capture('inspector_toggled', { enabled: enabled });
- this.setState({ inspectorEnabled: enabled });
- });
- Events.on('openscreenshotmodal', () => {
- posthog.capture('screenshot_modal_opened');
- this.setState({ isScreenshotOpen: true });
- });
- Events.on('opensigninmodal', () => {
- posthog.capture('signin_modal_opened');
- this.setState({ isSignInModalOpened: true });
- });
- Events.on('openscenesmodal', () => {
- posthog.capture('scenes_modal_opened');
- this.setState({ isScenesModalOpened: true });
- });
- Events.on('openprofilemodal', () => {
- posthog.capture('profile_modal_opened');
- this.setState({ isProfileModalOpened: true });
- });
- Events.on('opengeomodal', () => {
- posthog.capture('geo_modal_opened');
- this.setState({ isGeoModalOpened: true });
- });
- Events.on('openpaymentmodal', () => {
- posthog.capture('payment_modal_opened');
- this.setState({ isPaymentModalOpened: true });
- });
- Events.on('hideAddLayerPanel', () => {
- this.setState({ isAddLayerPanelOpen: false });
- });
- }
-
- toggleAddLayerPanel = () => {
- posthog.capture('add_layer_panel_opened');
- this.setState((prevState) => ({
- isAddLayerPanelOpen: !prevState.isAddLayerPanelOpen
- }));
};
- onCloseScreenshotModal = (value) => {
- this.setState({ isScreenshotOpen: false });
- };
-
- onModalTextureOnClose = (value) => {
- this.setState({ isModalTexturesOpen: false });
- if (this.state.textureOnClose) {
- this.state.textureOnClose(value);
+ const onModalTextureOnClose = (value) => {
+ setState((prevState) => ({
+ ...prevState,
+ isModalTexturesOpen: false
+ }));
+ if (state.textureOnClose) {
+ state.textureOnClose(value);
}
};
- onCloseSignInModal = () => {
- this.setState({ isSignInModalOpened: false });
- };
-
- onCloseScenesModal = () => {
- this.setState({ isScenesModalOpened: false });
- };
-
- onCloseProfileModal = () => {
- this.setState({ isProfileModalOpened: false });
- };
-
- onCloseGeoModal = () => {
- this.setState({ isGeoModalOpened: false });
- };
-
- onCloseIntroModal = () => {
- this.setState({ isIntroModalOpened: false });
- localStorage.setItem('shownIntro', true);
- };
-
- onClosePaymentModal = () => {
- window.location.hash = '#';
- this.setState({ isPaymentModalOpened: false });
- };
-
- renderComponentsToggle() {
- if (
- !this.state.inspectorEnabled ||
- !this.state.entity ||
- this.state.visible.attributes
- ) {
- return null;
- }
-
- return (
-
- );
- }
-
- renderSceneGraphToggle() {
- if (!this.state.inspectorEnabled || this.state.visible.scenegraph) {
- return null;
- }
- return (
-
- );
- }
-
- render() {
- const scene = this.state.sceneEl;
- const isEditor = !!this.state.inspectorEnabled;
-
- return (
-
- {this.renderSceneGraphToggle()}
- {this.renderComponentsToggle()}
-
- {isEditor && (
-
-
state.isInspectorEnabled);
+
+ return (
+
+
+ {isInspectorEnabled && (
+
+
+
- )}
-
-
-
-
-
-
-
-
-
-
-
- {this.state.inspectorEnabled && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ {isInspectorEnabled && (
+ <>
- )}
- {this.state.inspectorEnabled && (
- )}
- {this.state.inspectorEnabled && (
- )}
- {this.state.inspectorEnabled && (
- )}
- {this.state.inspectorEnabled && (
-
- )}
-
- );
- }
+ >
+ )}
+
+ );
}
diff --git a/src/editor/components/components/ActionBar/ActionBar.component.jsx b/src/editor/components/components/ActionBar/ActionBar.component.jsx
index 5f5e5831a..0bfc1d891 100644
--- a/src/editor/components/components/ActionBar/ActionBar.component.jsx
+++ b/src/editor/components/components/ActionBar/ActionBar.component.jsx
@@ -7,8 +7,12 @@ import { Button } from '../Button';
import { useState, useEffect } from 'react';
import posthog from 'posthog-js';
import { Rotate24Icon, Translate24Icon } from '../../../icons';
+import useStore from '@/store.js';
+
+const ActionBar = ({ selectedEntity }) => {
+ const setModal = useStore((state) => state.setModal);
+ const isOpen = useStore((state) => state.modal === 'addlayer');
-const ActionBar = ({ handleAddClick, isAddLayerPanelOpen, selectedEntity }) => {
const [cursorEnabled, setCursorEnabled] = useState(
AFRAME.INSPECTOR.cursor.isPlaying
);
@@ -42,7 +46,7 @@ const ActionBar = ({ handleAddClick, isAddLayerPanelOpen, selectedEntity }) => {
return (
- {!isAddLayerPanelOpen && (
+ {!isOpen && (
{
>
-
+ setModal('addlayer')}>
diff --git a/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx b/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx
index 5719e5980..fbc5f36bb 100644
--- a/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx
+++ b/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx
@@ -14,6 +14,7 @@ import Events from '../../../lib/Events';
import pickPointOnGroundPlane from '../../../lib/pick-point-on-ground-plane';
import { customLayersData, streetLayersData } from './layersData.js';
import { LayersOptions } from './LayersOptions.js';
+import useStore from '@/store.js';
// Create an empty image
const emptyImg = new Image();
@@ -266,13 +267,19 @@ const cardMouseLeave = (mixinId) => {
}
};
-const AddLayerPanel = ({ onClose, isAddLayerPanelOpen }) => {
+const AddLayerPanel = () => {
+ const setModal = useStore((state) => state.setModal);
+ const isOpen = useStore((state) => state.modal === 'addlayer');
// set the first Layers option when opening the panel
const [selectedOption, setSelectedOption] = useState(LayersOptions[0].value);
const [groupedMixins, setGroupedMixins] = useState([]);
const { currentUser } = useAuthContext();
const isProUser = currentUser && currentUser.isPro;
+ const onClose = () => {
+ setModal(null);
+ };
+
useEffect(() => {
// call getGroupedMixinOptions once time for getting mixinGroups
const data = getGroupedMixinOptions();
@@ -398,7 +405,7 @@ const AddLayerPanel = ({ onClose, isAddLayerPanelOpen }) => {
return (
{createPortal(
diff --git a/src/editor/components/components/GeoPanel/GeoPanel.component.jsx b/src/editor/components/components/GeoPanel/GeoPanel.component.jsx
index ad9d01599..67f984235 100644
--- a/src/editor/components/components/GeoPanel/GeoPanel.component.jsx
+++ b/src/editor/components/components/GeoPanel/GeoPanel.component.jsx
@@ -1,8 +1,8 @@
import GeoImg from '../../../../../ui_assets/geo.png';
import styles from './GeoPanel.module.scss';
-import Events from '../../../lib/Events';
import { useAuthContext, useGeoContext } from '../../../contexts/index.js';
import posthog from 'posthog-js';
+import useStore from '@/store';
/**
* GeoPanel component.
*
@@ -11,14 +11,16 @@ import posthog from 'posthog-js';
*/
const GeoPanel = () => {
const { currentUser } = useAuthContext();
+ const setModal = useStore((state) => state.setModal);
+
const onClick = () => {
posthog.capture('geo_panel_clicked');
if (!currentUser) {
- Events.emit('opensigninmodal');
+ setModal('signin');
} else if (currentUser.isPro) {
- Events.emit('opengeomodal');
+ setModal('geo');
} else {
- Events.emit('openpaymentmodal');
+ setModal('payment');
}
};
diff --git a/src/editor/components/components/Logo/Logo.component.jsx b/src/editor/components/components/Logo/Logo.component.jsx
index 5cfdad60d..0647c6373 100644
--- a/src/editor/components/components/Logo/Logo.component.jsx
+++ b/src/editor/components/components/Logo/Logo.component.jsx
@@ -1,27 +1,32 @@
import { Button } from '../Button';
-import PropTypes from 'prop-types';
import styles from './Logo.module.scss';
-
+import useStore from '@/store';
/**
* Logo component.
*
* @author Oleksii Medvediev
* @category Components
*/
-const Logo = ({ onToggleEdit, isEditor }) => (
-
-
-
-
-
- {isEditor ? 'Enter Viewer mode' : 'Enter Editor mode'}
-
-
-);
+const Logo = () => {
+ const setIsInspectorEnabled = useStore(
+ (state) => state.setIsInspectorEnabled
+ );
+ const isInspectorEnabled = useStore((state) => state.isInspectorEnabled);
-Logo.propTypes = {
- onToggleEdit: PropTypes.func,
- isEditor: PropTypes.bool
+ return (
+
+
+
+
+
setIsInspectorEnabled(!isInspectorEnabled)}
+ className={styles.btn}
+ variant="toolbtn"
+ >
+ {isInspectorEnabled ? 'Enter Viewer mode' : 'Enter Editor mode'}
+
+
+ );
};
export { Logo };
diff --git a/src/editor/components/components/ProfileButton/ProfileButton.component.jsx b/src/editor/components/components/ProfileButton/ProfileButton.component.jsx
index a2b8ab4a2..0dfc85240 100644
--- a/src/editor/components/components/ProfileButton/ProfileButton.component.jsx
+++ b/src/editor/components/components/ProfileButton/ProfileButton.component.jsx
@@ -1,12 +1,11 @@
import styles from './ProfileButton.module.scss';
import { Button } from '../Button';
-import Events from '../../../lib/Events.js';
import { Profile32Icon } from './icons.jsx';
import { useAuthContext } from '../../../contexts';
import posthog from 'posthog-js';
import MsftProfileImg from '../../../../../ui_assets/profile-microsoft.png';
-
+import useStore from '@/store';
/**
* ProfileButton component.
*
@@ -43,14 +42,14 @@ const renderProfileIcon = (currentUser) => {
const ProfileButton = () => {
const { currentUser } = useAuthContext();
-
+ const setModal = useStore((state) => state.setModal);
const onClick = async () => {
posthog.capture('profile_button_clicked', { is_logged_in: !!currentUser });
if (currentUser) {
- return Events.emit('openprofilemodal');
+ setModal('profile');
+ } else {
+ setModal('signin');
}
-
- return Events.emit('opensigninmodal');
};
return (
diff --git a/src/editor/components/modals/GeoModal/GeoModal.component.jsx b/src/editor/components/modals/GeoModal/GeoModal.component.jsx
index 4b651f9da..646ccf7d2 100644
--- a/src/editor/components/modals/GeoModal/GeoModal.component.jsx
+++ b/src/editor/components/modals/GeoModal/GeoModal.component.jsx
@@ -17,8 +17,9 @@ import {
import GeoImg from '../../../../../ui_assets/geo.png';
import { roundCoord } from '../../../../../src/utils.js';
import { QrCode } from '../../components/QrCode';
+import useStore from '@/store.js';
-const GeoModal = ({ isOpen, onClose }) => {
+const GeoModal = () => {
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: firebaseConfig.apiKey
});
@@ -30,6 +31,12 @@ const GeoModal = ({ isOpen, onClose }) => {
const [autocomplete, setAutocomplete] = useState(null);
const [qrCodeUrl, setQrCodeUrl] = useState(null);
const [isWorking, setIsWorking] = useState(false);
+ const setModal = useStore((state) => state.setModal);
+ const isOpen = useStore((state) => state.modal === 'geo');
+
+ const onClose = () => {
+ setModal(null);
+ };
useEffect(() => {
if (isOpen) {
diff --git a/src/editor/components/modals/IntroModal/IntroModal.component.jsx b/src/editor/components/modals/IntroModal/IntroModal.component.jsx
index 4037bd253..bbd77cfca 100644
--- a/src/editor/components/modals/IntroModal/IntroModal.component.jsx
+++ b/src/editor/components/modals/IntroModal/IntroModal.component.jsx
@@ -1,7 +1,13 @@
import Modal from '../Modal.jsx';
import MuxPlayer from '@mux/mux-player-react';
+import useStore from '@/store.js';
-const IntroModal = ({ isOpen, onClose }) => {
+const IntroModal = () => {
+ const isOpen = useStore((state) => state.modal === 'intro');
+ const onClose = () => {
+ useStore.getState().setModal(null);
+ localStorage.setItem('shownIntro', true);
+ };
return (
{
@@ -19,9 +20,11 @@ const getStripe = () => {
return stripePromise;
};
-const PaymentModal = ({ isOpen, onClose }) => {
+const PaymentModal = () => {
const { currentUser } = useAuthContext();
const [isLoading, setIsLoading] = useState(false);
+ const setModal = useStore((state) => state.setModal);
+ const modal = useStore((state) => state.modal);
if (location.hash.includes('success')) {
posthog.capture('checkout_finished');
@@ -59,8 +62,17 @@ const PaymentModal = ({ isOpen, onClose }) => {
setIsLoading(false);
};
+ const onClose = () => {
+ window.location.hash = '#';
+ setModal(null);
+ };
+
return (
-
+
Unlock Geospatial Features with a free 30 day trial
diff --git a/src/editor/components/modals/ProfileModal/ProfileModal.component.jsx b/src/editor/components/modals/ProfileModal/ProfileModal.component.jsx
index df3f50664..e521545f0 100644
--- a/src/editor/components/modals/ProfileModal/ProfileModal.component.jsx
+++ b/src/editor/components/modals/ProfileModal/ProfileModal.component.jsx
@@ -6,16 +6,23 @@ import { Button } from '../../components';
import { useAuthContext } from '../../../contexts';
import { signOut } from 'firebase/auth';
import { auth, functions } from '../../../services/firebase';
-import Events from '../../../lib/Events.js';
import { Action24, Loader } from '../../../icons';
import { httpsCallable } from 'firebase/functions';
import posthog from 'posthog-js';
import { renderProfileIcon } from '../../components/ProfileButton';
+import useStore from '@/store';
-const ProfileModal = ({ isOpen, onClose }) => {
+const ProfileModal = () => {
const { currentUser, setCurrentUser } = useAuthContext();
+ const setModal = useStore((state) => state.setModal);
+ const modal = useStore((state) => state.modal);
+
const [isLoading, setIsLoading] = useState(false);
+ const onClose = () => {
+ setModal(null);
+ };
+
const logOutHandler = async () => {
onClose();
await signOut(auth);
@@ -40,7 +47,11 @@ const ProfileModal = ({ isOpen, onClose }) => {
};
return (
-
+
3DStreet Cloud Account
@@ -110,7 +121,7 @@ const ProfileModal = ({ isOpen, onClose }) => {
{
onClose();
- Events.emit('openpaymentmodal');
+ setModal('payment');
}}
type="filled"
target="_blank"
diff --git a/src/editor/components/modals/ScenesModal/ScenesModal.component.jsx b/src/editor/components/modals/ScenesModal/ScenesModal.component.jsx
index 4d647c1a5..a068cb29d 100644
--- a/src/editor/components/modals/ScenesModal/ScenesModal.component.jsx
+++ b/src/editor/components/modals/ScenesModal/ScenesModal.component.jsx
@@ -25,7 +25,7 @@ const tabs = [
}
];
-const ScenesModal = ({ isOpen, onClose, initialTab = 'owner', delay }) => {
+const ScenesModal = ({ initialTab = 'owner', delay = undefined }) => {
const { currentUser } = useAuthContext();
const [renderComponent, setRenderComponent] = useState(!delay);
const [scenesData, setScenesData] = useState([]);
@@ -38,6 +38,8 @@ const ScenesModal = ({ isOpen, onClose, initialTab = 'owner', delay }) => {
const [isLoading, setIsLoading] = useState(false);
const [selectedTab, setSelectedTab] = useState(initialTab);
+ const setModal = useStore((state) => state.setModal);
+ const isOpen = useStore((state) => state.modal === 'scenes');
const handleSceneClick = (scene, event) => {
posthog.capture('scene_opened', {
scene_id: scene.id,
@@ -139,6 +141,10 @@ const ScenesModal = ({ isOpen, onClose, initialTab = 'owner', delay }) => {
fetchData();
}, [isOpen, currentUser, selectedTab]); // eslint-disable-line
+ const onClose = () => {
+ setModal(null);
+ };
+
const fetchUserScenes = async () => {
return await getUserScenes(currentUser?.uid);
};
diff --git a/src/editor/components/modals/ScreenshotModal/ScreenshotModal.component.jsx b/src/editor/components/modals/ScreenshotModal/ScreenshotModal.component.jsx
index cb4f62934..ccf157238 100644
--- a/src/editor/components/modals/ScreenshotModal/ScreenshotModal.component.jsx
+++ b/src/editor/components/modals/ScreenshotModal/ScreenshotModal.component.jsx
@@ -1,7 +1,6 @@
import { useEffect, useState } from 'react';
import styles from './ScreenshotModal.module.scss';
import { signIn } from '../../../api';
-import PropTypes from 'prop-types';
import { useAuthContext } from '../../../contexts';
import { Copy32Icon, Save24Icon } from '../../../icons';
import { Button, Dropdown, Input } from '../../components';
@@ -9,9 +8,8 @@ import Toolbar from '../../scenegraph/Toolbar';
import Modal from '../Modal.jsx';
import posthog from 'posthog-js';
import { saveBlob } from '../../../lib/utils';
-import Events from '../../../lib/Events';
import { uploadThumbnailImage, saveScreenshot } from '../../../api/scene';
-// import { loginHandler } from '../SignInModal';
+import useStore from '@/store';
const filterHelpers = (scene, visible) => {
scene.traverse((o) => {
@@ -41,41 +39,9 @@ const getSceneName = (scene) => {
return scene.id || slugify(window.location.host + window.location.pathname);
};
-const exportSceneToGLTF = (isPro) => {
- if (isPro) {
- try {
- const sceneName = getSceneName(AFRAME.scenes[0]);
- const scene = AFRAME.scenes[0].object3D;
- posthog.capture('export_scene_to_gltf_clicked', {
- scene_id: STREET.utils.getCurrentSceneId()
- });
-
- filterHelpers(scene, false);
- AFRAME.INSPECTOR.exporters.gltf.parse(
- scene,
- function (buffer) {
- filterHelpers(scene, true);
- const blob = new Blob([buffer], { type: 'application/octet-stream' });
- saveBlob(blob, sceneName + '.glb');
- },
- function (error) {
- console.error(error);
- },
- { binary: true }
- );
- STREET.notify.successMessage('3DStreet scene exported as glTF file.');
- } catch (error) {
- STREET.notify.errorMessage(
- `Error while trying to save glTF file. Error: ${error}`
- );
- console.error(error);
- }
- } else {
- Events.emit('openpaymentmodal');
- }
-};
-
-function ScreenshotModal({ isOpen, onClose }) {
+function ScreenshotModal() {
+ const setModal = useStore((state) => state.setModal);
+ const modal = useStore((state) => state.modal);
const storedScreenshot = localStorage.getItem('screenshot');
const parsedScreenshot = JSON.parse(storedScreenshot);
const { currentUser } = useAuthContext();
@@ -122,6 +88,42 @@ function ScreenshotModal({ isOpen, onClose }) {
setSelectedOption(value);
};
+ const exportSceneToGLTF = (isPro) => {
+ if (isPro) {
+ try {
+ const sceneName = getSceneName(AFRAME.scenes[0]);
+ const scene = AFRAME.scenes[0].object3D;
+ posthog.capture('export_scene_to_gltf_clicked', {
+ scene_id: STREET.utils.getCurrentSceneId()
+ });
+
+ filterHelpers(scene, false);
+ AFRAME.INSPECTOR.exporters.gltf.parse(
+ scene,
+ function (buffer) {
+ filterHelpers(scene, true);
+ const blob = new Blob([buffer], {
+ type: 'application/octet-stream'
+ });
+ saveBlob(blob, sceneName + '.glb');
+ },
+ function (error) {
+ console.error(error);
+ },
+ { binary: true }
+ );
+ STREET.notify.successMessage('3DStreet scene exported as glTF file.');
+ } catch (error) {
+ STREET.notify.errorMessage(
+ `Error while trying to save glTF file. Error: ${error}`
+ );
+ console.error(error);
+ }
+ } else {
+ setModal('payment');
+ }
+ };
+
const copyToClipboardTailing = async () => {
try {
const sceneId = STREET.utils.getCurrentSceneId();
@@ -146,8 +148,8 @@ function ScreenshotModal({ isOpen, onClose }) {
return (
setModal(null)}
title={'Share scene'}
titleElement={
<>
@@ -219,9 +221,4 @@ function ScreenshotModal({ isOpen, onClose }) {
);
}
-ScreenshotModal.propTypes = {
- isOpen: PropTypes.bool,
- onClose: PropTypes.func.isRequired
-};
-
export { ScreenshotModal };
diff --git a/src/editor/components/modals/SignInModal/SignInModal.component.jsx b/src/editor/components/modals/SignInModal/SignInModal.component.jsx
index 85ae3e8b9..675d6df4c 100644
--- a/src/editor/components/modals/SignInModal/SignInModal.component.jsx
+++ b/src/editor/components/modals/SignInModal/SignInModal.component.jsx
@@ -2,48 +2,61 @@ import { GoogleSignInButtonSVG, SignInMicrosoftIconSVG } from '../../../icons';
import Modal from '../Modal.jsx';
import styles from './SignInModal.module.scss';
import { signIn, signInMicrosoft } from '../../../api';
+import useStore from '@/store';
+const SignInModal = () => {
+ const setModal = useStore((state) => state.setModal);
+ const modal = useStore((state) => state.modal);
-const SignInModal = ({ isOpen, onClose }) => (
-
-
-
Sign in to 3DStreet Cloud
-
-
- Save and share your street scenes by clicking on a provider below to
- log-in or automatically create a{' '}
-
- 3DStreet Cloud account
- {' '}
- if you don't already have one.
-
-
-
{
- signIn();
- onClose();
- }}
- alt="Sign In with Google Button"
- className={styles.signInButton}
- >
-
-
-
{
- signInMicrosoft();
- onClose();
- }}
- alt="Sign In with Microsoft Button"
- className={styles.signInButton}
- style={{ transform: 'scale(0.85)' }}
- >
-
+ const onClose = () => {
+ setModal(null);
+ };
+
+ return (
+
+
+
Sign in to 3DStreet Cloud
+
+
+ Save and share your street scenes by clicking on a provider below to
+ log-in or automatically create a{' '}
+
+ 3DStreet Cloud account
+ {' '}
+ if you don't already have one.
+
+
+
{
+ signIn();
+ onClose();
+ }}
+ alt="Sign In with Google Button"
+ className={styles.signInButton}
+ >
+
+
+
{
+ signInMicrosoft();
+ onClose();
+ }}
+ alt="Sign In with Microsoft Button"
+ className={styles.signInButton}
+ style={{ transform: 'scale(0.85)' }}
+ >
+
+
-
-
-);
+
+ );
+};
export { SignInModal };
diff --git a/src/editor/components/scenegraph/Toolbar.js b/src/editor/components/scenegraph/Toolbar.js
index 12336ba0a..a80cf56d4 100644
--- a/src/editor/components/scenegraph/Toolbar.js
+++ b/src/editor/components/scenegraph/Toolbar.js
@@ -18,7 +18,8 @@ import posthog from 'posthog-js';
import { UndoRedo } from '../components/UndoRedo';
import debounce from 'lodash-es/debounce';
import { CameraToolbar } from '../viewport/CameraToolbar';
-import useStore from '../../../store';
+import useStore from '@/store';
+
// const LOCALSTORAGE_MOCAP_UI = "aframeinspectormocapuienabled";
/**
@@ -33,7 +34,7 @@ export default class Toolbar extends Component {
isSavingScene: false,
pendingSceneSave: false,
notification: null,
- inspectorEnabled: true
+ inspectorEnabled: useStore.getState().isInspectorEnabled
};
this.saveButtonRef = React.createRef();
}
@@ -46,9 +47,13 @@ export default class Toolbar extends Component {
this.debouncedCloudSaveHandler();
}
});
- Events.on('inspectortoggle', (enabled) => {
- this.setState({ inspectorEnabled: enabled });
- });
+ // Subscribe to store changes
+ this.unsubscribe = useStore.subscribe(
+ (state) => state.isInspectorEnabled,
+ (isInspectorEnabled) => {
+ this.setState({ inspectorEnabled: isInspectorEnabled });
+ }
+ );
}
componentDidUpdate(prevProps) {
@@ -63,6 +68,10 @@ export default class Toolbar extends Component {
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutsideSave);
+ // Unsubscribe from store changes
+ if (this.unsubscribe) {
+ this.unsubscribe();
+ }
}
isAuthor = () => {
@@ -140,7 +149,7 @@ export default class Toolbar extends Component {
if (!this.props.currentUser) {
console.log('no user');
- Events.emit('opensigninmodal');
+ useStore.getState().setModal('signin');
return;
}
@@ -154,7 +163,7 @@ export default class Toolbar extends Component {
streetGeo['latitude'] &&
streetGeo['longitude']
) {
- Events.emit('openpaymentmodal');
+ useStore.getState().setModal('payment');
return;
}
if (!this.isAuthor()) {
@@ -243,7 +252,7 @@ export default class Toolbar extends Component {
streetGeo['latitude'] &&
streetGeo['longitude']
) {
- Events.emit('openpaymentmodal');
+ useStore.getState().setModal('payment');
return;
}
this.cloudSaveHandler({ doSaveAs: false });
@@ -253,7 +262,7 @@ export default class Toolbar extends Component {
handleUnsignedSaveClick = () => {
posthog.capture('remix_scene_clicked');
this.setState({ pendingSceneSave: true });
- Events.emit('opensigninmodal');
+ useStore.getState().setModal('signin');
};
makeScreenshot = () => {
@@ -300,21 +309,13 @@ export default class Toolbar extends Component {
}));
};
- toggleEdit = () => {
- if (this.state.inspectorEnabled) {
- AFRAME.INSPECTOR.close();
- } else {
- AFRAME.INSPECTOR.open();
- }
- };
-
render() {
const isEditor = !!this.state.inspectorEnabled;
return (