diff --git a/lib/utils/wagmi-utils.js b/lib/utils/wagmi-utils.js
index befcd98a1..bd85ad0e1 100644
--- a/lib/utils/wagmi-utils.js
+++ b/lib/utils/wagmi-utils.js
@@ -1,38 +1,81 @@
// @flow
-import { configureChains, createClient } from 'wagmi';
+import { connectorsForWallets } from '@rainbow-me/rainbowkit';
+import {
+ injectedWallet,
+ metaMaskWallet,
+ rainbowWallet,
+ walletConnectWallet,
+ // eslint-disable-next-line import/extensions
+} from '@rainbow-me/rainbowkit/wallets';
+import * as React from 'react';
+import { configureChains, createClient, useProvider } from 'wagmi';
// eslint-disable-next-line import/extensions
import { mainnet } from 'wagmi/chains';
// eslint-disable-next-line import/extensions
import { alchemyProvider } from 'wagmi/providers/alchemy';
// eslint-disable-next-line import/extensions
import { publicProvider } from 'wagmi/providers/public';
+import { ENSCacheProvider } from '../components/ens-cache-provider.react.js';
+
// details can be found at https://wagmi.sh/core/providers/configuring-chains
type WagmiChainConfiguration = {
+chains: mixed,
+provider: mixed,
};
function configureWagmiChains(alchemyKey: ?string): WagmiChainConfiguration {
const availableProviders = alchemyKey
? [alchemyProvider({ apiKey: alchemyKey })]
: [publicProvider()];
const { chains, provider } = configureChains([mainnet], availableProviders);
return { chains, provider };
}
type WagmiClientInput = {
+provider: mixed,
+connectors?: mixed,
};
function createWagmiClient(input: WagmiClientInput): mixed {
const { provider, connectors } = input;
return createClient({
autoConnect: true,
connectors,
provider,
});
}
-export { configureWagmiChains, createWagmiClient };
+const { chains, provider } = configureWagmiChains(process.env.COMM_ALCHEMY_KEY);
+const connectors = connectorsForWallets([
+ {
+ groupName: 'Recommended',
+ wallets: [
+ injectedWallet({ chains }),
+ rainbowWallet({ chains }),
+ metaMaskWallet({ chains }),
+ walletConnectWallet({ chains }),
+ ],
+ },
+]);
+const wagmiClient: mixed = createWagmiClient({ connectors, provider });
+const wagmiChains: mixed = chains;
+
+type Props = {
+ +children: React.Node,
+};
+function WagmiENSCacheProvider(props: Props): React.Node {
+ const { children } = props;
+ const wagmiProvider = useProvider();
+ return (
+ {children}
+ );
+}
+
+export {
+ configureWagmiChains,
+ createWagmiClient,
+ wagmiClient,
+ wagmiChains,
+ WagmiENSCacheProvider,
+};
diff --git a/web/app.react.js b/web/app.react.js
index 52993dee8..9fadc7335 100644
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -1,348 +1,348 @@
// @flow
import 'basscss/css/basscss.min.css';
import './theme.css';
import { config as faConfig } from '@fortawesome/fontawesome-svg-core';
import classnames from 'classnames';
import _isEqual from 'lodash/fp/isEqual.js';
import * as React from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { useDispatch } from 'react-redux';
import { WagmiConfig } from 'wagmi';
import {
fetchEntriesActionTypes,
updateCalendarQueryActionTypes,
} from 'lib/actions/entry-actions.js';
import {
ModalProvider,
useModalContext,
} from 'lib/components/modal-provider.react.js';
import {
createLoadingStatusSelector,
combineLoadingStatuses,
} from 'lib/selectors/loading-selectors.js';
import { unreadCount } from 'lib/selectors/thread-selectors.js';
import { isLoggedIn } from 'lib/selectors/user-selectors.js';
import type { LoadingStatus } from 'lib/types/loading-types.js';
import type { Dispatch } from 'lib/types/redux-types.js';
import { registerConfig } from 'lib/utils/config.js';
+import { WagmiENSCacheProvider, wagmiClient } from 'lib/utils/wagmi-utils.js';
import AppsDirectory from './apps/apps-directory.react.js';
import Calendar from './calendar/calendar.react.js';
import Chat from './chat/chat.react.js';
import { TooltipProvider } from './chat/tooltip-provider.js';
import NavigationArrows from './components/navigation-arrows.react.js';
import electron from './electron.js';
import InputStateContainer from './input/input-state-container.react.js';
import LoadingIndicator from './loading-indicator.react.js';
import { MenuProvider } from './menu-provider.react.js';
import UpdateModalHandler from './modals/update-modal.react.js';
import SettingsSwitcher from './navigation-panels/settings-switcher.react.js';
import Topbar from './navigation-panels/topbar.react.js';
import { updateNavInfoActionType } from './redux/action-types.js';
import DeviceIDUpdater from './redux/device-id-updater.js';
import DisconnectedBarVisibilityHandler from './redux/disconnected-bar-visibility-handler.js';
import DisconnectedBar from './redux/disconnected-bar.js';
import FocusHandler from './redux/focus-handler.react.js';
import PolicyAcknowledgmentHandler from './redux/policy-acknowledgment-handler.js';
import { useSelector } from './redux/redux-utils.js';
import VisibilityHandler from './redux/visibility-handler.react.js';
import history from './router-history.js';
import AccountSettings from './settings/account-settings.react.js';
import DangerZone from './settings/danger-zone.react.js';
import CommunityPicker from './sidebar/community-picker.react.js';
import Splash from './splash/splash.react.js';
import './typography.css';
import css from './style.css';
import getTitle from './title/getTitle.js';
import { type NavInfo } from './types/nav-types.js';
import { canonicalURLFromReduxState, navInfoFromURL } from './url-utils.js';
-import { WagmiENSCacheProvider, wagmiClient } from './utils/wagmi-utils.js';
// We want Webpack's css-loader and style-loader to handle the Fontawesome CSS,
// so we disable the autoAddCss logic and import the CSS file. Otherwise every
// icon flashes huge for a second before the CSS is loaded.
import '@fortawesome/fontawesome-svg-core/styles.css';
faConfig.autoAddCss = false;
registerConfig({
// We can't securely cache credentials on web, so we have no way to recover
// from a cookie invalidation
resolveInvalidatedCookie: null,
// We use httponly cookies on web to protect against XSS attacks, so we have
// no access to the cookies from JavaScript
setCookieOnRequest: false,
setSessionIDOnRequest: true,
// Never reset the calendar range
calendarRangeInactivityLimit: null,
platformDetails: { platform: 'web' },
});
type BaseProps = {
+location: {
+pathname: string,
...
},
};
type Props = {
...BaseProps,
// Redux state
+navInfo: NavInfo,
+entriesLoadingStatus: LoadingStatus,
+loggedIn: boolean,
+activeThreadCurrentlyUnread: boolean,
// Redux dispatch functions
+dispatch: Dispatch,
+modals: $ReadOnlyArray,
};
class App extends React.PureComponent {
componentDidMount() {
const {
navInfo,
location: { pathname },
loggedIn,
} = this.props;
const newURL = canonicalURLFromReduxState(navInfo, pathname, loggedIn);
if (pathname !== newURL) {
history.replace(newURL);
}
}
componentDidUpdate(prevProps: Props) {
const {
navInfo,
location: { pathname },
loggedIn,
} = this.props;
if (!_isEqual(navInfo)(prevProps.navInfo)) {
const newURL = canonicalURLFromReduxState(navInfo, pathname, loggedIn);
if (newURL !== pathname) {
history.push(newURL);
}
} else if (pathname !== prevProps.location.pathname) {
const newNavInfo = navInfoFromURL(pathname, { navInfo });
if (!_isEqual(newNavInfo)(navInfo)) {
this.props.dispatch({
type: updateNavInfoActionType,
payload: newNavInfo,
});
}
} else if (loggedIn !== prevProps.loggedIn) {
const newURL = canonicalURLFromReduxState(navInfo, pathname, loggedIn);
if (newURL !== pathname) {
history.replace(newURL);
}
}
if (loggedIn !== prevProps.loggedIn) {
electron?.clearHistory();
}
}
onWordmarkClicked = () => {
this.props.dispatch({
type: updateNavInfoActionType,
payload: { tab: 'chat' },
});
};
render() {
let content;
if (this.props.loggedIn) {
content = this.renderMainContent();
} else {
content = ;
}
return (
{content}
{this.props.modals}
);
}
onHeaderDoubleClick = () => electron?.doubleClickTopBar();
stopDoubleClickPropagation = electron ? e => e.stopPropagation() : null;
renderMainContent() {
const mainContent = this.getMainContentWithSwitcher();
let navigationArrows = null;
if (electron) {
navigationArrows = ;
}
const headerClasses = classnames({
[css.header]: true,
[css['electron-draggable']]: electron,
});
const wordmarkClasses = classnames({
[css.wordmark]: true,
[css['electron-non-draggable']]: electron,
});
return (
);
}
getMainContentWithSwitcher() {
const { tab, settingsSection } = this.props.navInfo;
let mainContent;
if (tab === 'settings') {
if (settingsSection === 'account') {
mainContent = ;
} else if (settingsSection === 'danger-zone') {
mainContent = ;
}
return (
);
}
if (tab === 'calendar') {
mainContent = ;
} else if (tab === 'chat') {
mainContent = ;
} else if (tab === 'apps') {
mainContent = ;
}
const mainContentClass = classnames(
css['main-content-container'],
css['main-content-container-column'],
);
return (
);
}
}
const fetchEntriesLoadingStatusSelector = createLoadingStatusSelector(
fetchEntriesActionTypes,
);
const updateCalendarQueryLoadingStatusSelector = createLoadingStatusSelector(
updateCalendarQueryActionTypes,
);
const ConnectedApp: React.ComponentType = React.memo(
function ConnectedApp(props) {
const activeChatThreadID = useSelector(
state => state.navInfo.activeChatThreadID,
);
const navInfo = useSelector(state => state.navInfo);
const fetchEntriesLoadingStatus = useSelector(
fetchEntriesLoadingStatusSelector,
);
const updateCalendarQueryLoadingStatus = useSelector(
updateCalendarQueryLoadingStatusSelector,
);
const entriesLoadingStatus = combineLoadingStatuses(
fetchEntriesLoadingStatus,
updateCalendarQueryLoadingStatus,
);
const loggedIn = useSelector(isLoggedIn);
const activeThreadCurrentlyUnread = useSelector(
state =>
!activeChatThreadID ||
!!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread,
);
const boundUnreadCount = useSelector(unreadCount);
React.useEffect(() => {
document.title = getTitle(boundUnreadCount);
electron?.setBadge(boundUnreadCount === 0 ? null : boundUnreadCount);
}, [boundUnreadCount]);
const dispatch = useDispatch();
const modalContext = useModalContext();
const modals = React.useMemo(
() =>
modalContext.modals.map(([modal, key]) => (
{modal}
)),
[modalContext.modals],
);
return (
);
},
);
function AppWithProvider(props: BaseProps): React.Node {
return (
);
}
export default AppWithProvider;
diff --git a/web/splash/splash.react.js b/web/splash/splash.react.js
index 57240a715..6e3817820 100644
--- a/web/splash/splash.react.js
+++ b/web/splash/splash.react.js
@@ -1,39 +1,40 @@
// @flow
import { darkTheme, RainbowKitProvider } from '@rainbow-me/rainbowkit';
import _merge from 'lodash/fp/merge.js';
import * as React from 'react';
+import { wagmiChains } from 'lib/utils/wagmi-utils.js';
+
import css from './splash.css';
import LoginForm from '../account/log-in-form.react.js';
-import { wagmiChains } from '../utils/wagmi-utils.js';
function Splash(): React.Node {
const rainbowKitTheme = React.useMemo(() => {
return _merge(darkTheme())({
radii: {
modal: 0,
modalMobile: 0,
},
colors: {
modalBackdrop: '#242529',
},
});
}, []);
return (
);
}
export default Splash;
diff --git a/web/utils/wagmi-utils.js b/web/utils/wagmi-utils.js
deleted file mode 100644
index 0ed96d1eb..000000000
--- a/web/utils/wagmi-utils.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// @flow
-
-import { connectorsForWallets } from '@rainbow-me/rainbowkit';
-import {
- injectedWallet,
- rainbowWallet,
- metaMaskWallet,
- walletConnectWallet,
- // eslint-disable-next-line import/extensions
-} from '@rainbow-me/rainbowkit/wallets';
-import * as React from 'react';
-import { useProvider } from 'wagmi';
-
-import { ENSCacheProvider } from 'lib/components/ens-cache-provider.react.js';
-import {
- configureWagmiChains,
- createWagmiClient,
-} from 'lib/utils/wagmi-utils.js';
-
-const { chains, provider } = configureWagmiChains(process.env.COMM_ALCHEMY_KEY);
-const connectors = connectorsForWallets([
- {
- groupName: 'Recommended',
- wallets: [
- injectedWallet({ chains }),
- rainbowWallet({ chains }),
- metaMaskWallet({ chains }),
- walletConnectWallet({ chains }),
- ],
- },
-]);
-const wagmiClient: mixed = createWagmiClient({ connectors, provider });
-const wagmiChains: mixed = chains;
-
-type Props = {
- +children: React.Node,
-};
-function WagmiENSCacheProvider(props: Props): React.Node {
- const { children } = props;
- const wagmiProvider = useProvider();
- return (
- {children}
- );
-}
-
-export { wagmiClient, wagmiChains, WagmiENSCacheProvider };