mirror of https://github.com/mue/mue.git
refactor(header): Move to consistent header component for modal elements
Co-authored-by: David Ralph <me@davidcralph.co.uk>
This commit is contained in:
parent
84c1bc8df1
commit
6f00709c3d
|
@ -0,0 +1,23 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
class ErrorBoundary extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { hasError: false };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
this.setState({ hasError: true });
|
||||
console.error('Error boundary caught an error:', error, errorInfo);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return <div>Mue has broken horribly</div>;
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary;
|
|
@ -18,6 +18,8 @@ import {
|
|||
} from 'react-icons/md';
|
||||
import Modal from 'react-modal';
|
||||
|
||||
import Header from '../settings/Header';
|
||||
|
||||
import { install, uninstall } from 'modules/helpers/marketplace';
|
||||
|
||||
import ShareModal from 'components/helpers/sharemodal/ShareModal';
|
||||
|
@ -104,14 +106,12 @@ class Item extends PureComponent {
|
|||
modalClose={() => this.setState({ shareModal: false })}
|
||||
/>
|
||||
</Modal>
|
||||
<div className="flexTopMarketplace">
|
||||
<span className="mainTitle" onClick={this.props.toggleFunction}>
|
||||
<span className="backTitle">
|
||||
{variables.getMessage('modals.main.navbar.marketplace')}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight /> {this.props.data.data.display_name}
|
||||
</span>
|
||||
</div>
|
||||
<Header
|
||||
title={variables.getMessage('modals.main.navbar.marketplace')}
|
||||
secondaryTitle={this.props.data.data.display_name}
|
||||
report={false}
|
||||
goBack={this.props.toggleFunction}
|
||||
/>
|
||||
<div className="itemPage">
|
||||
<div className="itemShowcase">
|
||||
{this.props.data.data.photos && (
|
||||
|
|
|
@ -9,6 +9,7 @@ import FileUpload from '../../settings/FileUpload';
|
|||
import Item from '../Item';
|
||||
import Items from '../Items';
|
||||
import Dropdown from '../../settings/Dropdown';
|
||||
import Header from '../../settings/Header';
|
||||
|
||||
import { install, uninstall, urlParser } from 'modules/helpers/marketplace';
|
||||
|
||||
|
@ -70,6 +71,19 @@ export default class Added extends PureComponent {
|
|||
variables.stats.postEvent('marketplace', 'Sideload');
|
||||
}
|
||||
|
||||
getSideloadButton() {
|
||||
return (
|
||||
<button
|
||||
className="sideload"
|
||||
onClick={() => document.getElementById('file-input').click()}
|
||||
ref={this.customDnd}
|
||||
>
|
||||
{variables.getMessage('modals.main.addons.sideload.title')}
|
||||
<MdCode />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
toggle(type, data) {
|
||||
if (type === 'item') {
|
||||
const installed = JSON.parse(localStorage.getItem('installed'));
|
||||
|
@ -193,18 +207,9 @@ export default class Added extends PureComponent {
|
|||
if (this.state.installed.length === 0) {
|
||||
return (
|
||||
<>
|
||||
<div className="flexTopMarketplace topAddons">
|
||||
<span className="mainTitle">{variables.getMessage('modals.main.navbar.addons')}</span>
|
||||
{sideLoadBackendElements()}
|
||||
<button
|
||||
className="sideload"
|
||||
onClick={() => document.getElementById('file-input').click()}
|
||||
ref={this.customDnd}
|
||||
>
|
||||
{variables.getMessage('modals.main.addons.sideload.title')}
|
||||
<MdCode />
|
||||
</button>
|
||||
</div>
|
||||
<Header title={variables.getMessage('modals.main.navbar.addons')} report={false}>
|
||||
{this.getSideloadButton()}
|
||||
</Header>
|
||||
<div className="emptyItems">
|
||||
<div className="emptyNewMessage">
|
||||
<MdOutlineExtensionOff />
|
||||
|
@ -232,7 +237,7 @@ export default class Added extends PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="flexTopMarketplace topAddons">
|
||||
<div className="modalHeader">
|
||||
<span className="mainTitle">{variables.getMessage('modals.main.addons.added')}</span>
|
||||
<div className="filter">
|
||||
{sideLoadBackendElements()}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import Item from '../Item';
|
||||
import Items from '../Items';
|
||||
import Dropdown from '../../settings/Dropdown';
|
||||
import Header from '../../settings/Header';
|
||||
|
||||
import { install, urlParser, uninstall } from 'modules/helpers/marketplace';
|
||||
|
||||
|
@ -325,15 +326,12 @@ class Marketplace extends PureComponent {
|
|||
<>
|
||||
{this.state.collection === true ? (
|
||||
<>
|
||||
<div className="flexTopMarketplace">
|
||||
<span className="mainTitle" onClick={() => this.returnToMain()}>
|
||||
<span className="backTitle">
|
||||
{variables.getMessage('modals.main.navbar.marketplace')}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight />{' '}
|
||||
{variables.getMessage('modals.main.marketplace.collection')}
|
||||
</span>
|
||||
</div>
|
||||
<Header
|
||||
title={variables.getMessage('modals.main.navbar.marketplace')}
|
||||
secondaryTitle={variables.getMessage('modals.main.marketplace.collection')}
|
||||
report={false}
|
||||
goBack={() => this.returnToMain()}
|
||||
/>
|
||||
<div
|
||||
className="collectionPage"
|
||||
style={{
|
||||
|
|
|
@ -508,3 +508,18 @@ a.collectionButton {
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.modalHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.tooltip {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.mainTitle {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,100 +1,95 @@
|
|||
import variables from 'modules/variables';
|
||||
|
||||
import { PureComponent } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
/*MdHelpOutline,*/ MdFlag,
|
||||
MdArrowBack,
|
||||
MdFlag,
|
||||
MdOutlineVisibilityOff,
|
||||
MdOutlineVisibility,
|
||||
MdOutlineKeyboardArrowRight,
|
||||
} from 'react-icons/md';
|
||||
|
||||
import Slider from './Slider';
|
||||
import EventBus from 'modules/helpers/eventbus';
|
||||
|
||||
import { values } from 'modules/helpers/settings/modals';
|
||||
import Tooltip from 'components/helpers/tooltip/Tooltip';
|
||||
const Header = (props) => {
|
||||
const [setting, setSetting] = useState(localStorage.getItem(props.setting) === 'true');
|
||||
|
||||
class Header extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
[this.props.setting]: localStorage.getItem(this.props.setting) === 'true',
|
||||
};
|
||||
}
|
||||
useEffect(() => {
|
||||
setSetting(localStorage.getItem(props.setting) === 'true');
|
||||
}, [props.setting]);
|
||||
|
||||
changeSetting() {
|
||||
if (localStorage.getItem(this.props.setting) === 'true') {
|
||||
localStorage.setItem(this.props.setting, false);
|
||||
this.setState({ [this.props.setting]: false });
|
||||
EventBus.emit('toggle', this.props.setting);
|
||||
} else {
|
||||
localStorage.setItem(this.props.setting, true);
|
||||
this.setState({ [this.props.setting]: true });
|
||||
EventBus.emit('toggle', this.props.setting);
|
||||
}
|
||||
const changeSetting = () => {
|
||||
const toggle = localStorage.getItem(props.setting) === 'true';
|
||||
localStorage.setItem(props.setting, !toggle);
|
||||
setSetting(!toggle);
|
||||
|
||||
variables.stats.postEvent(
|
||||
'setting',
|
||||
`${this.props.name} ${this.state.checked === true ? 'enabled' : 'disabled'}`,
|
||||
`${props.name} ${setting === true ? 'enabled' : 'disabled'}`,
|
||||
);
|
||||
|
||||
if (this.props.element) {
|
||||
if (!document.querySelector(this.props.element)) {
|
||||
EventBus.emit('toggle', props.setting);
|
||||
|
||||
if (props.element) {
|
||||
if (!document.querySelector(props.element)) {
|
||||
document.querySelector('.reminder-info').style.display = 'flex';
|
||||
return localStorage.setItem('showReminder', true);
|
||||
}
|
||||
}
|
||||
|
||||
EventBus.emit('refresh', this.props.category);
|
||||
}
|
||||
EventBus.emit('refresh', props.category);
|
||||
};
|
||||
|
||||
render() {
|
||||
const VisibilityToggle = () => (
|
||||
<button className="sideload" onClick={changeSetting}>
|
||||
{setting ? (
|
||||
<>
|
||||
Hide
|
||||
<MdOutlineVisibilityOff />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Show
|
||||
<MdOutlineVisibility />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
|
||||
const ReportButton = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="flexTopMarketplace topAddons">
|
||||
{this.props.backButton && (
|
||||
<div className="returnButton" onClick={this.props.clickEffect}>
|
||||
<Tooltip
|
||||
title={variables.getMessage('modals.main.navbar.marketplace.product.buttons.back')}
|
||||
key="backArrow"
|
||||
>
|
||||
<MdArrowBack className="backArrow" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
<span className="mainTitle">{this.props.title}</span>
|
||||
<div className="headerActions">
|
||||
{this.props.switch && (
|
||||
<button className="sideload" onClick={() => this.changeSetting()}>
|
||||
{this.state[this.props.setting] ? (
|
||||
<>
|
||||
Hide
|
||||
<MdOutlineVisibilityOff />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Show
|
||||
<MdOutlineVisibility />
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="sideload"
|
||||
onClick={() =>
|
||||
window.open(
|
||||
variables.constants.BUG_REPORT + this.props.title.split(' ').join('+'),
|
||||
'_blank',
|
||||
)
|
||||
}
|
||||
>
|
||||
{variables.getMessage('modals.main.settings.sections.header.report_issue')} <MdFlag />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
<button
|
||||
className="sideload"
|
||||
onClick={() =>
|
||||
window.open(variables.constants.BUG_REPORT + props.title.split(' ').join('+'), '_blank')
|
||||
}
|
||||
>
|
||||
{variables.getMessage('modals.main.settings.sections.header.report_issue')} <MdFlag />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="modalHeader">
|
||||
<span className="mainTitle">
|
||||
{props.secondaryTitle ? (
|
||||
<>
|
||||
<span className="backTitle" onClick={props.goBack}>
|
||||
{props.title}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight />
|
||||
{props.secondaryTitle}
|
||||
</>
|
||||
) : (
|
||||
<>{props.title}</>
|
||||
)}
|
||||
</span>
|
||||
<div className="headerActions">
|
||||
{props.switch && <VisibilityToggle />}
|
||||
{props.report !== false && <ReportButton />}
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
|
|
@ -17,6 +17,7 @@ import Text from '../Text';
|
|||
import Switch from '../Switch';
|
||||
import ResetModal from '../ResetModal';
|
||||
import Dropdown from '../Dropdown';
|
||||
import Header from '../Header';
|
||||
|
||||
import { Row, Content, Action } from '../SettingsItem';
|
||||
import Section from '../Section';
|
||||
|
@ -64,18 +65,15 @@ export default function AdvancedSettings() {
|
|||
let header;
|
||||
if (data) {
|
||||
header = (
|
||||
<span className="mainTitle">
|
||||
<span className="backTitle" onClick={() => setData(false)}>
|
||||
{variables.getMessage(`${ADVANCED_SECTION}.title`)}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight />
|
||||
{variables.getMessage(`${ADVANCED_SECTION}.data`)}
|
||||
</span>
|
||||
<Header
|
||||
title={variables.getMessage(`${ADVANCED_SECTION}.title`)}
|
||||
secondaryTitle={variables.getMessage(`${ADVANCED_SECTION}.data`)}
|
||||
goBack={() => setData(false)}
|
||||
report={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
header = (
|
||||
<span className="mainTitle"> {variables.getMessage(`${ADVANCED_SECTION}.title`)}</span>
|
||||
);
|
||||
header = <Header title={variables.getMessage(`${ADVANCED_SECTION}.title`)} report={false} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -7,6 +7,7 @@ import Dropdown from '../Dropdown';
|
|||
import Radio from '../Radio';
|
||||
import Slider from '../Slider';
|
||||
import Text from '../Text';
|
||||
import Header from '../Header';
|
||||
|
||||
import { Row, Content, Action } from '../SettingsItem';
|
||||
|
||||
|
@ -234,20 +235,21 @@ function AppearanceSettings() {
|
|||
let header;
|
||||
if (accessibility) {
|
||||
header = (
|
||||
<span className="mainTitle">
|
||||
<span className="backTitle" onClick={() => setAccessibility(false)}>
|
||||
{variables.getMessage('modals.main.settings.sections.appearance.title')}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight />
|
||||
{variables.getMessage('modals.main.settings.sections.appearance.accessibility.title')}
|
||||
</span>
|
||||
<Header
|
||||
title={variables.getMessage('modals.main.settings.sections.appearance.title')}
|
||||
secondaryTitle={variables.getMessage(
|
||||
'modals.main.settings.sections.appearance.accessibility.title',
|
||||
)}
|
||||
goBack={() => setAccessibility(false)}
|
||||
report={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
header = (
|
||||
<span className="mainTitle">
|
||||
{' '}
|
||||
{variables.getMessage('modals.main.settings.sections.appearance.title')}
|
||||
</span>
|
||||
<Header
|
||||
title={variables.getMessage('modals.main.settings.sections.appearance.title')}
|
||||
report={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class LanguageSettings extends PureComponent {
|
|||
render() {
|
||||
return (
|
||||
<>
|
||||
<div className="flexTopMarketplace topAddons">
|
||||
<div className="modalHeader">
|
||||
<span className="mainTitle">
|
||||
{variables.getMessage('modals.main.settings.sections.language.title')}
|
||||
</span>
|
||||
|
|
|
@ -247,11 +247,14 @@ export default class QuoteSettings extends PureComponent {
|
|||
return (
|
||||
<>
|
||||
{this.state.sourceSection ? (
|
||||
<span className="mainTitle" onClick={() => this.setState({ sourceSection: false })}>
|
||||
<span className="backTitle">{variables.getMessage(`${QUOTE_SECTION}.title`)}</span>
|
||||
<MdOutlineKeyboardArrowRight />{' '}
|
||||
{variables.getMessage('modals.main.settings.sections.background.source.title')}
|
||||
</span>
|
||||
<Header
|
||||
title={variables.getMessage(`${QUOTE_SECTION}.title`)}
|
||||
secondaryTitle={variables.getMessage(
|
||||
'modals.main.settings.sections.background.source.title',
|
||||
)}
|
||||
goBack={() => this.setState({ sourceSection: false })}
|
||||
report={false}
|
||||
/>
|
||||
) : (
|
||||
<Header
|
||||
title={variables.getMessage(`${QUOTE_SECTION}.title`)}
|
||||
|
|
|
@ -267,26 +267,23 @@ export default class BackgroundSettings extends PureComponent {
|
|||
let header;
|
||||
if (this.state.effects === true) {
|
||||
header = (
|
||||
<span className="mainTitle" onClick={() => this.setState({ effects: false })}>
|
||||
<span className="backTitle">
|
||||
{variables.getMessage('modals.main.settings.sections.background.title')}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight />{' '}
|
||||
{variables.getMessage('modals.main.settings.sections.background.effects.title')}
|
||||
</span>
|
||||
<Header
|
||||
title={variables.getMessage('modals.main.settings.sections.background.title')}
|
||||
secondaryTitle={variables.getMessage(
|
||||
'modals.main.settings.sections.background.effects.title',
|
||||
)}
|
||||
goBack={() => this.setState({ effects: false })}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.backgroundSettingsSection === true) {
|
||||
header = (
|
||||
<span
|
||||
className="mainTitle"
|
||||
onClick={() => this.setState({ backgroundSettingsSection: false })}
|
||||
>
|
||||
<span className="backTitle">
|
||||
{variables.getMessage('modals.main.settings.sections.background.title')}{' '}
|
||||
</span>
|
||||
<MdOutlineKeyboardArrowRight />{' '}
|
||||
{variables.getMessage('modals.main.settings.sections.background.source.title')}
|
||||
</span>
|
||||
<Header
|
||||
title={variables.getMessage('modals.main.settings.sections.background.title')}
|
||||
secondaryTitle={variables.getMessage(
|
||||
'modals.main.settings.sections.background.source.title',
|
||||
)}
|
||||
goBack={() => this.setState({ backgroundSettingsSection: false })}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
header = (
|
||||
|
|
|
@ -75,48 +75,44 @@ class Tabs extends PureComponent {
|
|||
{reminderInfo}
|
||||
</ul>
|
||||
<div className="tab-content" style={{ width: '100%' }}>
|
||||
<ErrorBoundary>
|
||||
<div className="modalNavbar">
|
||||
<button
|
||||
className={
|
||||
this.props.current === 'settings'
|
||||
? 'navbar-item navbar-item-active'
|
||||
: 'navbar-item'
|
||||
}
|
||||
onClick={() => this.props.changeTab('settings')}
|
||||
>
|
||||
<MdSettings />
|
||||
<span>{variables.getMessage('modals.main.navbar.settings')}</span>
|
||||
</button>
|
||||
<button
|
||||
className={
|
||||
this.props.current === 'addons' ? 'navbar-item navbar-item-active' : 'navbar-item'
|
||||
}
|
||||
onClick={() => this.props.changeTab('addons')}
|
||||
>
|
||||
<MdOutlineExtension />
|
||||
<span>{variables.getMessage('modals.main.navbar.addons')}</span>
|
||||
</button>
|
||||
<button
|
||||
className={
|
||||
this.props.current === 'marketplace'
|
||||
? 'navbar-item navbar-item-active'
|
||||
: 'navbar-item'
|
||||
}
|
||||
onClick={() => this.props.changeTab('marketplace')}
|
||||
>
|
||||
<MdOutlineShoppingBasket />
|
||||
<span>{variables.getMessage('modals.main.navbar.marketplace')}</span>
|
||||
</button>
|
||||
</div>
|
||||
{this.props.children.map((tab) => {
|
||||
if (tab.props.label !== this.state.currentTab) {
|
||||
return undefined;
|
||||
<div className="modalNavbar">
|
||||
<button
|
||||
className={
|
||||
this.props.current === 'settings' ? 'navbar-item navbar-item-active' : 'navbar-item'
|
||||
}
|
||||
onClick={() => this.props.changeTab('settings')}
|
||||
>
|
||||
<MdSettings />
|
||||
<span>{variables.getMessage('modals.main.navbar.settings')}</span>
|
||||
</button>
|
||||
<button
|
||||
className={
|
||||
this.props.current === 'addons' ? 'navbar-item navbar-item-active' : 'navbar-item'
|
||||
}
|
||||
onClick={() => this.props.changeTab('addons')}
|
||||
>
|
||||
<MdOutlineExtension />
|
||||
<span>{variables.getMessage('modals.main.navbar.addons')}</span>
|
||||
</button>
|
||||
<button
|
||||
className={
|
||||
this.props.current === 'marketplace'
|
||||
? 'navbar-item navbar-item-active'
|
||||
: 'navbar-item'
|
||||
}
|
||||
onClick={() => this.props.changeTab('marketplace')}
|
||||
>
|
||||
<MdOutlineShoppingBasket />
|
||||
<span>{variables.getMessage('modals.main.navbar.marketplace')}</span>
|
||||
</button>
|
||||
</div>
|
||||
{this.props.children.map((tab) => {
|
||||
if (tab.props.label !== this.state.currentTab) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return tab.props.children;
|
||||
})}
|
||||
</ErrorBoundary>
|
||||
return <ErrorBoundary>{tab.props.children}</ErrorBoundary>;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { createRoot } from 'react-dom/client';
|
|||
import * as Sentry from '@sentry/react';
|
||||
|
||||
import App from './App';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
import variables from './modules/variables';
|
||||
|
||||
import './scss/index.scss';
|
||||
|
@ -27,4 +28,8 @@ Sentry.init({
|
|||
|
||||
const container = document.getElementById('root');
|
||||
const root = createRoot(container);
|
||||
root.render(<App />);
|
||||
root.render(
|
||||
<ErrorBoundary>
|
||||
<App />
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue