fixed uneccesary statu updates to prevent flashing rerenders on the wordlist etc

This commit is contained in:
lingdocs 2021-08-31 17:15:36 +04:00
parent 62cf2ef4d4
commit e69fd94d31
10 changed files with 66 additions and 71 deletions

View File

@ -150,8 +150,14 @@ function setupPassport(passport: PassportStatic) {
cb(null, false); cb(null, false);
return; return;
} }
const newUser = await updateLingdocsUser(userId, { lastActive: getTimestamp() }); try {
cb(null, newUser); // skip if there's an update conflict
const newUser = await updateLingdocsUser(userId, { lastActive: getTimestamp() });
cb(null, newUser);
} catch (e) {
console.error(e);
cb(null, user);
}
} catch (err) { } catch (err) {
cb(err, null); cb(err, null);
} }

View File

@ -200,9 +200,9 @@
} }
}, },
"@lingdocs/pashto-inflector": { "@lingdocs/pashto-inflector": {
"version": "0.9.0", "version": "0.9.2",
"resolved": "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.9.0.tgz", "resolved": "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.9.2.tgz",
"integrity": "sha512-kiWVshiMGp/eT0vPTheujD9hJrUXAqLKG48a6iqX8RBURlv5hjk9t+CymKvLGYDO0Zrog0kAYcSo/PqkV0UKIw==", "integrity": "sha512-9tmPPezEvPFR/tPkBuF/bj79dCAviFTGOmCVDbRCymXmv4gWWhH4lCueYOYhyWZ4vXcihMflVpRSmLtUDXmdjQ==",
"requires": { "requires": {
"classnames": "^2.2.6", "classnames": "^2.2.6",
"pbf": "^3.2.1", "pbf": "^3.2.1",
@ -1697,9 +1697,9 @@
} }
}, },
"protocol-buffers-schema": { "protocol-buffers-schema": {
"version": "3.5.1", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.2.tgz",
"integrity": "sha512-YVCvdhxWNDP8/nJDyXLuM+UFsuPk4+1PB7WGPVDzm3HTHbzFLxQYeW2iZpS4mmnXrQJGBzt230t/BbEb7PrQaw==" "integrity": "sha512-LPzSaBYp/TcbuSlpGwqT5jR9kvJ3Zp5ic2N5c2ybx6XB/lSfEHq2D7ja8AgoxHoMD91wXFALJoXsvshKPuXyew=="
}, },
"proxy-addr": { "proxy-addr": {
"version": "2.0.6", "version": "2.0.6",
@ -1745,9 +1745,9 @@
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
}, },
"rambda": { "rambda": {
"version": "6.8.2", "version": "6.9.0",
"resolved": "https://registry.npmjs.org/rambda/-/rambda-6.8.2.tgz", "resolved": "https://registry.npmjs.org/rambda/-/rambda-6.9.0.tgz",
"integrity": "sha512-fIVr6nuqfHfJTguthGsWF930DkNq/ENraeSpYBj1kYvO/ieacux7rj2NW27JwwFrllFJwXkLpGyFMz99EwCJ3Q==" "integrity": "sha512-yosVdGg1hNGkXPzqGiOYNEpXKjEOxzUCg2rB0l+NKdyCaSf4z+i5ojbN0IqDSezMMf71YEglI+ZUTgTffn5afw=="
}, },
"range-parser": { "range-parser": {
"version": "1.2.1", "version": "1.2.1",

View File

@ -14,7 +14,7 @@
"main": "lib/functions/src/index.js", "main": "lib/functions/src/index.js",
"dependencies": { "dependencies": {
"@google-cloud/storage": "^5.8.1", "@google-cloud/storage": "^5.8.1",
"@lingdocs/pashto-inflector": "^0.9.0", "@lingdocs/pashto-inflector": "^0.9.2",
"@types/cors": "^2.8.10", "@types/cors": "^2.8.10",
"@types/google-spreadsheet": "^3.0.2", "@types/google-spreadsheet": "^3.0.2",
"cors": "^2.8.5", "cors": "^2.8.5",

View File

@ -6,7 +6,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.15.2", "@fortawesome/fontawesome-free": "^5.15.2",
"@lingdocs/pashto-inflector": "^0.9.0", "@lingdocs/pashto-inflector": "^0.9.2",
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",
@ -32,7 +32,6 @@
"react-bootstrap": "^1.5.1", "react-bootstrap": "^1.5.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-dropzone": "^11.3.2", "react-dropzone": "^11.3.2",
"react-firebaseui": "^4.1.0",
"react-ga": "^3.3.0", "react-ga": "^3.3.0",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-image-crop": "^8.6.9", "react-image-crop": "^8.6.9",
@ -87,14 +86,14 @@
"@types/lokijs": "^1.5.3", "@types/lokijs": "^1.5.3",
"@types/mousetrap": "^1.6.8", "@types/mousetrap": "^1.6.8",
"@types/papaparse": "^5.2.5", "@types/papaparse": "^5.2.5",
"@types/passport-github2": "^1.2.5",
"@types/passport-google-oauth": "^1.0.42",
"@types/passport-twitter": "^1.0.37",
"@types/pouchdb": "^6.4.0", "@types/pouchdb": "^6.4.0",
"@types/react-canvas-draw": "^1.1.0", "@types/react-canvas-draw": "^1.1.0",
"@types/react-helmet": "^6.1.0", "@types/react-helmet": "^6.1.0",
"@types/react-image-crop": "^8.1.2", "@types/react-image-crop": "^8.1.2",
"@types/react-router-dom": "^5.1.7", "@types/react-router-dom": "^5.1.7",
"@types/passport-github2": "^1.2.5",
"@types/passport-google-oauth": "^1.0.42",
"@types/passport-twitter": "^1.0.37",
"fake-indexeddb": "^3.1.2", "fake-indexeddb": "^3.1.2",
"history": "4", "history": "4",
"jest-fetch-mock": "^3.0.3", "jest-fetch-mock": "^3.0.3",

View File

@ -73,6 +73,7 @@ import "./App.css";
import classNames from "classnames"; import classNames from "classnames";
import { getTextOptions } from "./lib/get-text-options"; import { getTextOptions } from "./lib/get-text-options";
import { getTextFromShareTarget } from "./lib/share-target"; import { getTextFromShareTarget } from "./lib/share-target";
import { objIsEqual } from "./lib/misc-helpers";
// to allow Moustrap key combos even when input fields are in focus // to allow Moustrap key combos even when input fields are in focus
Mousetrap.prototype.stopCallback = function () { Mousetrap.prototype.stopCallback = function () {
@ -290,8 +291,10 @@ class App extends Component<RouteComponentProps, State> {
...userOnServer, ...userOnServer,
userTextOptionsRecord, userTextOptionsRecord,
}; };
this.setState({ user }); if (!objIsEqual(prevUser, user)) {
saveUser(user); this.setState({ user });
saveUser(user);
}
const textOptionsRecord: TextOptionsRecord = { const textOptionsRecord: TextOptionsRecord = {
lastModified: userTextOptionsRecord.lastModified, lastModified: userTextOptionsRecord.lastModified,
textOptions: { textOptions: {
@ -345,7 +348,7 @@ class App extends Component<RouteComponentProps, State> {
this.setState({ options }); this.setState({ options });
} }
} else { } else {
this.setState({ options }); !objIsEqual(this.state.options, options) && this.setState({ options });
} }
} }
@ -514,7 +517,8 @@ class App extends Component<RouteComponentProps, State> {
</Route> </Route>
{wordlistEnabled(this.state.user) && <Route path="/wordlist"> {wordlistEnabled(this.state.user) && <Route path="/wordlist">
<Wordlist <Wordlist
state={this.state} options={this.state.options}
wordlist={this.state.wordlist}
isolateEntry={this.handleIsolateEntry} isolateEntry={this.handleIsolateEntry}
optionsDispatch={this.handleOptionsUpdate} optionsDispatch={this.handleOptionsUpdate}
/> />

View File

@ -8,6 +8,9 @@ const baseUrl: Record<Service, string> = {
functions: "https://functions.lingdocs.com/", functions: "https://functions.lingdocs.com/",
}; };
// @ts-ignore
const sampleAdminUser: AT.LingdocsUser = {"_id":"5e8dd381-950f-4641-922d-c63c6bf0f8e9","_rev":"1713-1a299e0d66da62fe4c8d059f0f068cb7","userId":"5e8dd381-950f-4641-922d-c63c6bf0f8e9","email":"clay@mailbox.org","admin":true,"emailVerified":true,"name":"Adam D","password":"$2a$10$JR4AHXXGbFP6sKQrqGO9UuMa3tdzNhbdqBvkjn2MVBuIOHkA/Xkf.","level":"editor","tests":[],"lastLogin":1629893763810,"lastActive":1630414108552,"userTextOptionsRecord":{"lastModified":1629983812750,"userTextOptions":{"spelling":"Afghan","diacritics":false,"dialect":"standard","phonetics":"lingdocs"}},"github":{"id":"71590811","nodeId":"MDQ6VXNlcjcxNTkwODEx","displayName":"LingDocs","username":"lingdocs","profileUrl":"https://github.com/lingdocs","photos":[{"value":"https://avatars.githubusercontent.com/u/71590811?v=4"}],"provider":"github","accessToken":"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"},"twitter":{"id":"1307635660451385344","username":"lingdocs","displayName":"LingDocs","photos":[{"value":"https://pbs.twimg.com/profile_images/1315656283928899584/EJIqjI-I_normal.jpg"}],"provider":"twitter","_accessLevel":"read","token":"1307635660451385344-MhpGAaJ6hFmfJtV97N6gy11FgbamVX","tokenSecret":"QjouJ33sWb2MpCkcUqqRxbfC9bqDyRaIODO9cejDvdusN"},"wordlistDbName":"userdb-35653864643338312d393530662d343634312d393232642d633633633662663066386539","couchDbPassword":"oevewi8iptdqyxax3v1x7t2ngi4uloir53g2y4659ada","google":{"id":"111202697753203366308","displayName":"Adam Dueck","name":{"familyName":"Dueck","givenName":"Adam"},"emails":[{"value":"lingdocsdev@gmail.com","verified":true}],"photos":[{"value":"https://lh3.googleusercontent.com/a/AATXAJx3cxPPpUoosqVzyGR-LcJ48EjpVcOBInkW21E=s96-c"}],"provider":"google","accessToken":"ya29.a0ARrdaM8BOOmaKxAPe_tKuVq0VgBncURPeEUUqV85RKksibmdx-DSY0IPOGXLs7UB8vh0yIpULsCQHiBKKg_l1DtuEmfwkN7F1h5YDyn2Zwd_ytVTE4W93YvdVGHVnX8rTdlEVcXLO2apwhJrBi3PuzTzxa6BTw"}};
// FUNCTIONS CALLS - MUST BE RE-ROUTED THROUGH FIREBASE HOSTING IN ../../../firebase.json // FUNCTIONS CALLS - MUST BE RE-ROUTED THROUGH FIREBASE HOSTING IN ../../../firebase.json
export async function publishDictionary(): Promise<FT.PublishDictionaryResponse | FT.FunctionError> { export async function publishDictionary(): Promise<FT.PublishDictionaryResponse | FT.FunctionError> {
return await myFetch("functions", "publishDictionary") as FT.PublishDictionaryResponse | FT.FunctionError; return await myFetch("functions", "publishDictionary") as FT.PublishDictionaryResponse | FT.FunctionError;
@ -41,6 +44,9 @@ export async function signOut() {
} }
export async function getUser(): Promise<undefined | AT.LingdocsUser | "offline"> { export async function getUser(): Promise<undefined | AT.LingdocsUser | "offline"> {
if (process.env.REACT_APP_ENV === "dev") {
return sampleAdminUser;
}
try { try {
const response = await myFetch("account", "user"); const response = await myFetch("account", "user");
if ("user" in response) { if ("user" in response) {

View File

@ -0,0 +1,4 @@
export function objIsEqual(obj1: any, obj2: any): boolean {
if (!obj1 || !obj2) return false;
return JSON.stringify(obj1) === JSON.stringify(obj2);
}

View File

@ -44,7 +44,6 @@ import AudioPlayButton from "../components/AudioPlayButton";
import dayjs from "dayjs"; import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime.js"; import relativeTime from "dayjs/plugin/relativeTime.js";
import hitBottom from "../lib/hitBottom"; import hitBottom from "../lib/hitBottom";
import { getTextOptions } from "../lib/get-text-options";
const cleanupIcon = "broom"; const cleanupIcon = "broom";
@ -72,8 +71,9 @@ function amountOfWords(number: number): string {
return `${number} word${number !== 1 ? "s" : ""}`; return `${number} word${number !== 1 ? "s" : ""}`;
} }
function Wordlist({ state, isolateEntry, optionsDispatch }: { function Wordlist({ options, wordlist, isolateEntry, optionsDispatch }: {
state: State, options: Options,
wordlist: WordlistWord[],
isolateEntry: (ts: number) => void, isolateEntry: (ts: number) => void,
optionsDispatch: (action: OptionsAction) => void, optionsDispatch: (action: OptionsAction) => void,
}) { }) {
@ -89,17 +89,17 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
const [showingCleanup, setShowingCleanup] = useState<boolean>(false); const [showingCleanup, setShowingCleanup] = useState<boolean>(false);
const [monthsBackToKeep, setMonthsBackToKeep] = useState<number>(6); const [monthsBackToKeep, setMonthsBackToKeep] = useState<number>(6);
const [wordsToDelete, setWordsToDelete] = useState<string[]>([]); const [wordsToDelete, setWordsToDelete] = useState<string[]>([]);
const [startedWithWordsToReview] = useState<boolean>(forReview(state.wordlist).length !== 0); const [startedWithWordsToReview] = useState<boolean>(forReview(wordlist).length !== 0);
useEffect(() => { useEffect(() => {
window.addEventListener("scroll", handleScroll); window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll);
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, []);
const toReview = forReview(state.wordlist); const toReview = forReview(wordlist);
const textOptions = getTextOptions(state); const textOptions = options.textOptionsRecord.textOptions;
function handleScroll() { function handleScroll() {
// TODO: DON'T HAVE ENDLESS PAGE INCREASING // TODO: DON'T HAVE ENDLESS PAGE INCREASING
if (hitBottom() && state.options.wordlistMode === "browse") { if (hitBottom() && options.wordlistMode === "browse") {
setPage(page => page + 1); setPage(page => page + 1);
} }
} }
@ -119,7 +119,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
} }
function handleSearchValueChange(value: string) { function handleSearchValueChange(value: string) {
setWordlistSearchValue(value); setWordlistSearchValue(value);
const results = value ? searchWordlist(value, state.wordlist, textOptions) : []; const results = value ? searchWordlist(value, wordlist, textOptions) : [];
setFilteredWords(results); setFilteredWords(results);
} }
async function handleGetWordlistCSV() { async function handleGetWordlistCSV() {
@ -137,7 +137,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
} }
function handleShowCleanup() { function handleShowCleanup() {
setWordsToDelete( setWordsToDelete(
calculateWordsToDelete(state.wordlist, monthsBackToKeep) calculateWordsToDelete(wordlist, monthsBackToKeep)
); );
setShowingCleanup(true); setShowingCleanup(true);
} }
@ -146,7 +146,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
setWordsToDelete([]); setWordsToDelete([]);
} }
function handleCleanup() { function handleCleanup() {
const toDelete = calculateWordsToDelete(state.wordlist, monthsBackToKeep); const toDelete = calculateWordsToDelete(wordlist, monthsBackToKeep);
deleteWordFromWordlist(toDelete); deleteWordFromWordlist(toDelete);
setShowingCleanup(false); setShowingCleanup(false);
} }
@ -219,13 +219,13 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
<div className="card mb-3 clickable" onClick={() => handleWordClickReview(word._id)}> <div className="card mb-3 clickable" onClick={() => handleWordClickReview(word._id)}>
<div className="card-body"> <div className="card-body">
<h6 className="card-title text-center"> <h6 className="card-title text-center">
{state.options.wordlistReviewLanguage === "Pashto" {options.wordlistReviewLanguage === "Pashto"
? <InlinePs opts={textOptions}>{{ p: word.entry.p, f: word.entry.f }}</InlinePs> ? <InlinePs opts={textOptions}>{{ p: word.entry.p, f: word.entry.f }}</InlinePs>
: word.entry.e : word.entry.e
} }
</h6> </h6>
{beingQuizzed && <div className="card-text text-center"> {beingQuizzed && <div className="card-text text-center">
{state.options.wordlistReviewLanguage === "Pashto" {options.wordlistReviewLanguage === "Pashto"
? <div>{word.entry.e}</div> ? <div>{word.entry.e}</div>
: <InlinePs opts={textOptions}> : <InlinePs opts={textOptions}>
{{ p: word.entry.p, f: word.entry.f }} {{ p: word.entry.p, f: word.entry.f }}
@ -249,7 +249,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
</Helmet> </Helmet>
<div className="d-flex flex-row justify-content-between mb-2"> <div className="d-flex flex-row justify-content-between mb-2">
<h4 className="mb-3">Wordlist</h4> <h4 className="mb-3">Wordlist</h4>
{state.wordlist.length > 0 && {wordlist.length > 0 &&
<div className="d-flex flex-row justify-content-between mb-2"> <div className="d-flex flex-row justify-content-between mb-2">
<div> <div>
<button className="btn btn-sm btn-outline-secondary mr-3" onClick={handleShowCleanup}> <button className="btn btn-sm btn-outline-secondary mr-3" onClick={handleShowCleanup}>
@ -264,7 +264,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
</div> </div>
} }
</div> </div>
{!state.wordlist.length ? {!wordlist.length ?
<EmptyWordlistNotice /> <EmptyWordlistNotice />
: :
<> <>
@ -280,16 +280,16 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
value: "review", value: "review",
}, },
]} ]}
value={state.options.wordlistMode || "browse"} value={options.wordlistMode || "browse"}
handleChange={(p) => { handleChange={(p) => {
optionsDispatch({ type: "changeWordlistMode", payload: p as WordlistMode }); optionsDispatch({ type: "changeWordlistMode", payload: p as WordlistMode });
}} }}
/> />
</div> </div>
{state.options.wordlistMode === "browse" {options.wordlistMode === "browse"
? <div className="mt-4"> ? <div className="mt-4">
<WordlistSearchBar value={wordlistSearchValue} handleChange={handleSearchValueChange} /> <WordlistSearchBar value={wordlistSearchValue} handleChange={handleSearchValueChange} />
{paginate(wordlistSearchValue ? filteredWords : state.wordlist, page).map((word) => ( {paginate(wordlistSearchValue ? filteredWords : wordlist, page).map((word) => (
<WordlistBrowsingWord word={word} key={word._id} /> <WordlistBrowsingWord word={word} key={word._id} />
))} ))}
</div> </div>
@ -298,7 +298,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
<div className="mb-4 text-center" style={{ width: "100%" }}> <div className="mb-4 text-center" style={{ width: "100%" }}>
<ButtonSelect <ButtonSelect
options={reviewLanguageOptions} options={reviewLanguageOptions}
value={state.options.wordlistReviewLanguage || "Pashto"} value={options.wordlistReviewLanguage || "Pashto"}
handleChange={(p) => { handleChange={(p) => {
optionsDispatch({ type: "changeWordlistReviewLanguage", payload: p as Language }); optionsDispatch({ type: "changeWordlistReviewLanguage", payload: p as Language });
}} }}
@ -310,7 +310,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
? (startedWithWordsToReview ? (startedWithWordsToReview
? <p className="lead my-3">All done review 🎉</p> ? <p className="lead my-3">All done review 🎉</p>
: (() => { : (() => {
const nextUp = nextUpForReview(state.wordlist); const nextUp = nextUpForReview(wordlist);
const { e, ...ps } = nextUp.entry; const { e, ...ps } = nextUp.entry;
return <div> return <div>
<div className="lead my-3">None to review</div> <div className="lead my-3">None to review</div>
@ -370,7 +370,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
<Modal.Title><i className={`fas fa-${cleanupIcon} mr-1`} /> Wordlist Cleanup</Modal.Title> <Modal.Title><i className={`fas fa-${cleanupIcon} mr-1`} /> Wordlist Cleanup</Modal.Title>
</Modal.Header> </Modal.Header>
<Modal.Body> <Modal.Body>
<p>You have {amountOfWords(state.wordlist.length)} in your wordlist.</p> <p>You have {amountOfWords(wordlist.length)} in your wordlist.</p>
<p>Delete words older than:</p> <p>Delete words older than:</p>
<ButtonSelect <ButtonSelect
options={[ options={[
@ -391,7 +391,7 @@ function Wordlist({ state, isolateEntry, optionsDispatch }: {
handleChange={(p: string) => { handleChange={(p: string) => {
const months = parseInt(p); const months = parseInt(p);
setWordsToDelete( setWordsToDelete(
calculateWordsToDelete(state.wordlist, months), calculateWordsToDelete(wordlist, months),
); );
setMonthsBackToKeep(months); setMonthsBackToKeep(months);
}} }}

View File

@ -10,6 +10,7 @@
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"downlevelIteration": true,
"strict": true, "strict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,

View File

@ -1483,10 +1483,10 @@
"@types/yargs" "^16.0.0" "@types/yargs" "^16.0.0"
chalk "^4.0.0" chalk "^4.0.0"
"@lingdocs/pashto-inflector@^0.9.0": "@lingdocs/pashto-inflector@^0.9.2":
version "0.9.0" version "0.9.2"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.9.0.tgz#d4aa0154f65b27b27cafdbbd1881d00aa1cc43cb" resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.9.2.tgz#7ef3b3344c3eb3e3d1db77142ef83f0ac7e8e230"
integrity sha512-kiWVshiMGp/eT0vPTheujD9hJrUXAqLKG48a6iqX8RBURlv5hjk9t+CymKvLGYDO0Zrog0kAYcSo/PqkV0UKIw== integrity sha512-9tmPPezEvPFR/tPkBuF/bj79dCAviFTGOmCVDbRCymXmv4gWWhH4lCueYOYhyWZ4vXcihMflVpRSmLtUDXmdjQ==
dependencies: dependencies:
classnames "^2.2.6" classnames "^2.2.6"
pbf "^3.2.1" pbf "^3.2.1"
@ -4781,11 +4781,6 @@ detect-port-alt@1.1.6:
address "^1.0.1" address "^1.0.1"
debug "^2.6.0" debug "^2.6.0"
dialog-polyfill@^0.4.7:
version "0.4.10"
resolved "https://registry.yarnpkg.com/dialog-polyfill/-/dialog-polyfill-0.4.10.tgz#c4ea68a0deed4abb59a6a2a025c548b278cd532e"
integrity sha512-j5yGMkP8T00UFgyO+78OxiN5vC5dzRQF3BEio+LhNvDbyfxWBsi3sfPArDm54VloaJwy2hm3erEiDWqHRC8rzw==
diff-sequences@^26.6.2: diff-sequences@^26.6.2:
version "26.6.2" version "26.6.2"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
@ -5837,14 +5832,6 @@ find-up@^3.0.0:
dependencies: dependencies:
locate-path "^3.0.0" locate-path "^3.0.0"
firebaseui@^4.7.1:
version "4.8.1"
resolved "https://registry.yarnpkg.com/firebaseui/-/firebaseui-4.8.1.tgz#29ccbc9dfd579c4453725f88e9cf81c8ea62c580"
integrity sha512-Qh8kfqGjMIiVJ2X8MUFsmlf43QFcVc8ungD+kw5T8ACuhQ68IAyUHExlItAfumrcLlqEgyo1MjH0O9fZZAMOKw==
dependencies:
dialog-polyfill "^0.4.7"
material-design-lite "^1.2.0"
flat-cache@^3.0.4: flat-cache@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@ -8201,11 +8188,6 @@ map-visit@^1.0.0:
dependencies: dependencies:
object-visit "^1.0.0" object-visit "^1.0.0"
material-design-lite@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/material-design-lite/-/material-design-lite-1.3.0.tgz#d004ce3fee99a1eeb74a78b8a325134a5f1171d3"
integrity sha1-0ATOP+6Zoe63Sni4oyUTSl8RcdM=
md5.js@^1.3.4: md5.js@^1.3.4:
version "1.3.5" version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@ -10527,13 +10509,6 @@ react-fast-compare@^3.1.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-firebaseui@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/react-firebaseui/-/react-firebaseui-4.2.0.tgz#13846381daefe31b90af98854f3e79e82d4f81ba"
integrity sha512-KRWfQn7iJMMAcB1zmMrpo5PJ7CBrLW6NXvdEJ/N+SFZUs7ANvC3g8LzgYwsBHUr1OR1MQtGosV7dyQSmYtKyOA==
dependencies:
firebaseui "^4.7.1"
react-ga@^3.3.0: react-ga@^3.3.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.0.tgz#c91f407198adcb3b49e2bc5c12b3fe460039b3ca" resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.0.tgz#c91f407198adcb3b49e2bc5c12b3fe460039b3ca"