refactor(header): Move to consistent header component for modal elements

Co-authored-by: David Ralph <me@davidcralph.co.uk>
This commit is contained in:
alexsparkes 2024-02-10 10:45:21 +00:00
parent 84c1bc8df1
commit 6f00709c3d
13 changed files with 228 additions and 191 deletions

23
src/ErrorBoundary.jsx Normal file
View File

@ -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;

View File

@ -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 && (

View File

@ -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()}

View File

@ -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={{

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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 (

View File

@ -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 (

View File

@ -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>

View File

@ -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`)}

View File

@ -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 = (

View File

@ -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>
);

View File

@ -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>,
);