diff --git a/app/soapbox/features/onboarding/onboarding-wizard.tsx b/app/soapbox/features/onboarding/onboarding-wizard.tsx
index 7ef3cb804..bc85b63cc 100644
--- a/app/soapbox/features/onboarding/onboarding-wizard.tsx
+++ b/app/soapbox/features/onboarding/onboarding-wizard.tsx
@@ -67,7 +67,7 @@ const OnboardingWizard = () => {
}, []);
return (
-
+
diff --git a/app/soapbox/features/public_layout/components/pulse.tsx b/app/soapbox/features/public_layout/components/pulse.tsx
index 6aba78c32..33e94dae2 100644
--- a/app/soapbox/features/public_layout/components/pulse.tsx
+++ b/app/soapbox/features/public_layout/components/pulse.tsx
@@ -20,7 +20,7 @@ const Pulse: React.FC = () => {
setAnimationData(json);
})
.catch(console.error);
- });
+ }, []);
if (animationData) {
return (
diff --git a/app/soapbox/features/soapbox_config/components/site_preview.js b/app/soapbox/features/soapbox_config/components/site_preview.js
index b4506dd81..3d52d7200 100644
--- a/app/soapbox/features/soapbox_config/components/site_preview.js
+++ b/app/soapbox/features/soapbox_config/components/site_preview.js
@@ -52,5 +52,5 @@ export default function SitePreview({ soapbox }) {
}
SitePreview.propTypes = {
- soapbox: ImmutablePropTypes.map.isRequired,
+ soapbox: ImmutablePropTypes.record.isRequired,
};
diff --git a/app/soapbox/features/ui/components/promo_panel.tsx b/app/soapbox/features/ui/components/promo_panel.tsx
index 5a0b9a24d..6766a6ad4 100644
--- a/app/soapbox/features/ui/components/promo_panel.tsx
+++ b/app/soapbox/features/ui/components/promo_panel.tsx
@@ -18,8 +18,8 @@ const PromoPanel: React.FC = () => {
{promoItems.map((item, i) => (
-
-
+
+
{item.textLocales.get(locale) || item.text}
diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js
index 9af173cb3..f0761f1b1 100644
--- a/app/soapbox/features/ui/index.js
+++ b/app/soapbox/features/ui/index.js
@@ -188,7 +188,7 @@ class SwitchingColumnsArea extends React.PureComponent {
children: PropTypes.node,
location: PropTypes.object,
onLayoutChange: PropTypes.func.isRequired,
- soapbox: ImmutablePropTypes.map.isRequired,
+ soapbox: ImmutablePropTypes.record.isRequired,
features: PropTypes.object.isRequired,
};
@@ -399,7 +399,7 @@ class UI extends React.PureComponent {
streamingUrl: PropTypes.string,
account: PropTypes.object,
features: PropTypes.object.isRequired,
- soapbox: ImmutablePropTypes.map.isRequired,
+ soapbox: ImmutablePropTypes.record.isRequired,
vapidKey: PropTypes.string,
};
diff --git a/app/soapbox/jest/test-setup.ts b/app/soapbox/jest/test-setup.ts
index 82beb982a..6456e3e84 100644
--- a/app/soapbox/jest/test-setup.ts
+++ b/app/soapbox/jest/test-setup.ts
@@ -6,8 +6,12 @@ import { __clear as clearApiMocks } from '../__mocks__/api';
jest.mock('soapbox/api');
afterEach(() => clearApiMocks());
+// Mock IndexedDB
+// https://dev.to/andyhaskell/testing-your-indexeddb-code-with-jest-2o17
+require('fake-indexeddb/auto');
+
// Mock external dependencies
-jest.mock('uuid', () => ({ v4: jest.fn(() => 1) }));
+jest.mock('uuid', () => ({ v4: jest.fn(() => '1') }));
const intersectionObserverMock = () => ({ observe: () => null, disconnect: () => null });
window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock);
diff --git a/app/soapbox/locales/messages.js b/app/soapbox/locales/messages.ts
similarity index 67%
rename from app/soapbox/locales/messages.js
rename to app/soapbox/locales/messages.ts
index 129869d50..d9499697f 100644
--- a/app/soapbox/locales/messages.js
+++ b/app/soapbox/locales/messages.ts
@@ -1,16 +1,19 @@
-// Import custom messages
-const importCustom = locale => {
+type MessageJson = Record;
+type MessageModule = { default: MessageJson };
+
+/** Import custom messages */
+const importCustom = (locale: string): Promise => {
return import(/* webpackChunkName: "locale_[request]" */`custom/locales/${locale}.json`)
- .catch(error => ({ default: {} }));
+ .catch(() => ({ default: {} }));
};
-// Import git-checked messages
-const importMessages = locale => {
+/** Import git-checked messages */
+const importMessages = (locale: string): Promise => {
return import(/* webpackChunkName: "locale_[request]" */`./${locale}.json`);
};
-// Override custom messages
-const importMessagesWithCustom = locale => {
+/** Override custom messages */
+const importMessagesWithCustom = (locale: string): Promise => {
return Promise.all([
importMessages(locale),
importCustom(locale),
@@ -23,7 +26,7 @@ const importMessagesWithCustom = locale => {
});
};
-const locales = [
+const locales: string[] = [
'ar',
'ast',
'bg',
@@ -89,10 +92,10 @@ const locales = [
'zh-TW',
];
-// Build the export
+/** Soapbox locales map */
const messages = locales.reduce((acc, locale) => {
acc[locale] = () => importMessagesWithCustom(locale);
return acc;
-}, {});
+}, {} as Record Promise>);
export default messages;
diff --git a/app/soapbox/main.tsx b/app/soapbox/main.tsx
index 0a9bbdb75..9505ae07a 100644
--- a/app/soapbox/main.tsx
+++ b/app/soapbox/main.tsx
@@ -6,6 +6,7 @@ import React from 'react';
import ReactDOM from 'react-dom';
import * as BuildConfig from 'soapbox/build_config';
+import { printConsoleWarning } from 'soapbox/utils/console';
import { default as Soapbox } from './containers/soapbox';
import * as monitoring from './monitoring';
@@ -18,6 +19,11 @@ function main() {
// Sentry
monitoring.start();
+ // Print console warning
+ if (BuildConfig.NODE_ENV === 'production') {
+ printConsoleWarning();
+ }
+
ready(() => {
const mountNode = document.getElementById('soapbox') as HTMLElement;
diff --git a/app/soapbox/utils/console.ts b/app/soapbox/utils/console.ts
new file mode 100644
index 000000000..96f8b6b5e
--- /dev/null
+++ b/app/soapbox/utils/console.ts
@@ -0,0 +1,24 @@
+/** Print a warning to users not to copy-paste into the console */
+const printConsoleWarning = () => {
+ /* eslint-disable no-console */
+ console.log('%cStop!', [
+ 'color: #ff0000',
+ 'display: block',
+ 'font-family: system-ui, -apple-system, BlinkMacSystemFont, Ubuntu, "Helvetica Neue", sans-serif',
+ 'font-size: 50px',
+ 'font-weight: 800',
+ 'padding: 4px 0',
+ ].join(';'));
+ console.log('%cThis is a browser feature intended for developers. If someone told you to copy-paste something here it is a scam and will give them access to your account.', [
+ 'color: #111111',
+ 'display: block',
+ 'font-family: system-ui, -apple-system, BlinkMacSystemFont, Ubuntu, "Helvetica Neue", sans-serif',
+ 'font-size: 18px',
+ 'padding: 4px 0 16px',
+ ].join(';'));
+ /* eslint-enable no-console */
+};
+
+export {
+ printConsoleWarning,
+};
diff --git a/package.json b/package.json
index db202449f..128e3ccea 100644
--- a/package.json
+++ b/package.json
@@ -211,6 +211,7 @@
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.25.1",
"eslint-plugin-react-hooks": "^4.2.0",
+ "fake-indexeddb": "^3.1.7",
"husky": "^7.0.2",
"jest": "^27.5.1",
"lint-staged": ">=10",
diff --git a/yarn.lock b/yarn.lock
index d012a5b17..d7cd7c4db 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3084,6 +3084,11 @@ balanced-match@^2.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
+base64-arraybuffer-es6@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer-es6/-/base64-arraybuffer-es6-0.7.0.tgz#dbe1e6c87b1bf1ca2875904461a7de40f21abc86"
+ integrity sha512-ESyU/U1CFZDJUdr+neHRhNozeCv72Y7Vm0m1DCbjX3KBjT6eYocvAJlSk6+8+HkVwXlT1FNxhGW6q3UKAlCvvw==
+
batch@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
@@ -3708,6 +3713,11 @@ core-js@^3.1.3, core-js@^3.15.2:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.0.tgz#9af3f4a6df9ba3428a3fb1b171f1503b3f40cc49"
integrity sha512-WJeQqq6jOYgVgg4NrXKL0KLQhi0CT4ZOCvFL+3CQ5o7I6J8HkT5wd53EadMfqTDp1so/MT1J+w2ujhWcCJtN7w==
+core-js@^3.4:
+ version "3.22.2"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.2.tgz#3ea0a245b0895fa39d1faa15fe75d91ade504a01"
+ integrity sha512-Z5I2vzDnEIqO2YhELVMFcL1An2CIsFe9Q7byZhs8c/QxummxZlAHw33TUHbIte987LkisOgL0LwQ1P9D6VISnA==
+
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
@@ -4296,6 +4306,13 @@ domelementtype@^2.0.1, domelementtype@^2.2.0:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
+domexception@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
+ integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
+ dependencies:
+ webidl-conversions "^4.0.2"
+
domexception@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
@@ -4927,6 +4944,13 @@ extend@^3.0.0:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+fake-indexeddb@^3.1.7:
+ version "3.1.7"
+ resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-3.1.7.tgz#d9efbeade113c15efbe862e4598a4b0a1797ed9f"
+ integrity sha512-CUGeCzCOVjmeKi2C0pcvSh6NDU6uQIaS+7YyR++tO/atJJujkBYVhDvfePdz/U8bD33BMVWirsr1MKczfAqbjA==
+ dependencies:
+ realistic-structured-clone "^2.0.1"
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -9049,6 +9073,16 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
+realistic-structured-clone@^2.0.1:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-2.0.4.tgz#7eb4c2319fc3cb72f4c8d3c9e888b11647894b50"
+ integrity sha512-lItAdBIFHUSe6fgztHPtmmWqKUgs+qhcYLi3wTRUl4OTB3Vb8aBVSjGfQZUvkmJCKoX3K9Wf7kyLp/F/208+7A==
+ dependencies:
+ core-js "^3.4"
+ domexception "^1.0.1"
+ typeson "^6.1.0"
+ typeson-registry "^1.0.0-alpha.20"
+
rechoir@^0.7.0:
version "0.7.1"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686"
@@ -10440,6 +10474,20 @@ typescript@^4.4.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
+typeson-registry@^1.0.0-alpha.20:
+ version "1.0.0-alpha.39"
+ resolved "https://registry.yarnpkg.com/typeson-registry/-/typeson-registry-1.0.0-alpha.39.tgz#9e0f5aabd5eebfcffd65a796487541196f4b1211"
+ integrity sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==
+ dependencies:
+ base64-arraybuffer-es6 "^0.7.0"
+ typeson "^6.0.0"
+ whatwg-url "^8.4.0"
+
+typeson@^6.0.0, typeson@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/typeson/-/typeson-6.1.0.tgz#5b2a53705a5f58ff4d6f82f965917cabd0d7448b"
+ integrity sha512-6FTtyGr8ldU0pfbvW/eOZrEtEkczHRUtduBnA90Jh9kMPCiFNnXIon3vF41N0S4tV1HHQt4Hk1j4srpESziCaA==
+
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
@@ -10730,6 +10778,11 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies:
minimalistic-assert "^1.0.0"
+webidl-conversions@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
+ integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+
webidl-conversions@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
@@ -10914,7 +10967,7 @@ whatwg-mimetype@^2.3.0:
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
-whatwg-url@^8.0.0, whatwg-url@^8.5.0:
+whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0:
version "8.7.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==