fixed uneccesary statu updates to prevent flashing rerenders on the wordlist etc
This commit is contained in:
parent
62cf2ef4d4
commit
e69fd94d31
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export function objIsEqual(obj1: any, obj2: any): boolean {
|
||||||
|
if (!obj1 || !obj2) return false;
|
||||||
|
return JSON.stringify(obj1) === JSON.stringify(obj2);
|
||||||
|
}
|
|
@ -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);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue