diff --git a/account/src/lib/sample-users.ts b/account/src/lib/sample-users.ts index b4cb621..545b127 100644 --- a/account/src/lib/sample-users.ts +++ b/account/src/lib/sample-users.ts @@ -79,9 +79,12 @@ const editor: AT.LingdocsUser = { }, }; -export default { +// @ts-ignore +const users: any = { basic, student, editor, admin, }; + +export default users; diff --git a/dist/website/src/types/account-types.d.ts b/dist/website/src/types/account-types.d.ts index e23422c..1783e8f 100644 --- a/dist/website/src/types/account-types.d.ts +++ b/dist/website/src/types/account-types.d.ts @@ -20,6 +20,7 @@ export declare type EmailVerified = true | Hash | false; export declare type ActionComplete = { ok: true; message: string; + tests?: TestResult[]; }; export declare type ActionError = { ok: false; @@ -48,6 +49,11 @@ export declare type UserTextOptionsRecord = { lastModified: TimeStamp; userTextOptions: UserTextOptions; }; +export declare type TestResult = { + done: true; + time: TimeStamp; + id: string; +}; export declare type LingdocsUser = { userId: UUID; admin?: boolean; @@ -63,7 +69,7 @@ export declare type LingdocsUser = { requestedOn: TimeStamp; }; upgradeToStudentRequest?: "waiting" | "denied"; - tests: []; + tests: TestResult[]; lastLogin: TimeStamp; lastActive: TimeStamp; userTextOptionsRecord: undefined | UserTextOptionsRecord; @@ -88,6 +94,14 @@ export declare type UpgradeUserResponse = { message: "user already upgraded" | "user upgraded to student"; user: LingdocsUser; }; +export declare type PostTestResultsBody = { + tests: TestResult[]; +}; +export declare type PostTestResultsResponse = { + ok: true; + message: "posted test results"; + tests: TestResult[]; +}; export declare type UpdateUserTextOptionsRecordBody = { userTextOptionsRecord: UserTextOptionsRecord; }; diff --git a/library.ts b/library.ts index c7a7d61..f9ba011 100644 --- a/library.ts +++ b/library.ts @@ -1,5 +1,6 @@ import * as AT from "./website/src/types/account-types"; import * as FT from "./website/src/types/functions-types"; +import * as DT from "./website/src/types/dictionary-types"; import { getTimestamp, } from "./account/src/lib/time-utils"; @@ -54,4 +55,5 @@ export { // TYPES AT, FT, + DT, }; diff --git a/package.json b/package.json index c52abda..43e4d91 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lingdocs/lingdocs-main", - "version": "0.2.8", + "version": "0.2.9", "description": "types and functions for lingdocs stuff", "main": "dist/library.js", "module": "dist/library.js", diff --git a/website/src/App.tsx b/website/src/App.tsx index 57ed5c4..4caaf01 100644 --- a/website/src/App.tsx +++ b/website/src/App.tsx @@ -74,6 +74,12 @@ import classNames from "classnames"; import { getTextOptions } from "./lib/get-text-options"; import { getTextFromShareTarget } from "./lib/share-target"; import { objIsEqual, userObjIsEqual } from "./lib/misc-helpers"; +import { + State, + TextOptionsRecord, + TextOptionsAction, + OptionsAction, +} from "./types/dictionary-types"; // to allow Moustrap key combos even when input fields are in focus Mousetrap.prototype.stopCallback = function () { diff --git a/website/src/components/AudioPlayButton.tsx b/website/src/components/AudioPlayButton.tsx index e086cc4..f40adc9 100644 --- a/website/src/components/AudioPlayButton.tsx +++ b/website/src/components/AudioPlayButton.tsx @@ -10,6 +10,7 @@ import { useEffect, useState } from "react"; import { getAudioAttachment, } from "../lib/wordlist-database"; +import { WordlistWord } from "../types/dictionary-types"; export function AudioPlayButton({ word }: { word: WordlistWord }) { const [src, setSrc] = useState(undefined); diff --git a/website/src/components/DictionaryStatusDisplay.tsx b/website/src/components/DictionaryStatusDisplay.tsx index 7a56f07..e12be94 100644 --- a/website/src/components/DictionaryStatusDisplay.tsx +++ b/website/src/components/DictionaryStatusDisplay.tsx @@ -6,6 +6,8 @@ * */ +import { DictionaryStatus } from "../types/dictionary-types"; + function DictionaryStatusDisplay({ status }: { status: DictionaryStatus }) { if (status === "loading" || status === "updating") { return ( diff --git a/website/src/components/ImageEditor.tsx b/website/src/components/ImageEditor.tsx index 339d315..7127144 100644 --- a/website/src/components/ImageEditor.tsx +++ b/website/src/components/ImageEditor.tsx @@ -12,6 +12,7 @@ import { updateWordlistWord, } from "../lib/wordlist-database"; import WordlistImage from "./WordlistImage"; +import { WordlistWord } from "../types/dictionary-types"; // TODO: !! remember to save the new dimensions whenever modifying the image diff --git a/website/src/components/InflectionSearchResult.tsx b/website/src/components/InflectionSearchResult.tsx index 13b9a6e..8e311fa 100644 --- a/website/src/components/InflectionSearchResult.tsx +++ b/website/src/components/InflectionSearchResult.tsx @@ -14,6 +14,10 @@ import { displayFormResult, displayPositionResult, } from "../lib/inflection-search-helpers"; +import { + InflectionSearchResult, + InflectionName, +} from "../types/dictionary-types"; function InflectionSearchResult( { result, textOptions, entry }: diff --git a/website/src/components/SearchBar.tsx b/website/src/components/SearchBar.tsx index fb09ac6..dfee4bf 100644 --- a/website/src/components/SearchBar.tsx +++ b/website/src/components/SearchBar.tsx @@ -7,6 +7,12 @@ */ import { useRef } from "react"; +import { State } from "../types/dictionary-types"; +import { + OptionsAction, + Language, + SearchType, +} from "../types/dictionary-types"; const SearchBar = ({ state, optionsDispatch, handleSearchValueChange, onBottom }: { state: State diff --git a/website/src/components/WordlistImage.tsx b/website/src/components/WordlistImage.tsx index 8f8c219..ea4151a 100644 --- a/website/src/components/WordlistImage.tsx +++ b/website/src/components/WordlistImage.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import { getImageAttachment } from "../lib/wordlist-database"; +import { WordlistWord } from "../types/dictionary-types"; function WordlistImage({ word }: { word: WordlistWord }) { const [imgSrc, setImgSrc] = useState(undefined); diff --git a/website/src/components/WordlistWordEditor.tsx b/website/src/components/WordlistWordEditor.tsx index 45c1e2b..2f4657b 100644 --- a/website/src/components/WordlistWordEditor.tsx +++ b/website/src/components/WordlistWordEditor.tsx @@ -14,6 +14,7 @@ import { updateWordlistWord, hasAttachment, } from "../lib/wordlist-database"; +import { WordlistWord } from "../types/dictionary-types"; const droppingStyle = { boxShadow: "0 0 5px rgba(81, 203, 238, 1)", diff --git a/website/src/lib/__mocks__/wordlist-database.ts b/website/src/lib/__mocks__/wordlist-database.ts index 04f0c89..f95990f 100644 --- a/website/src/lib/__mocks__/wordlist-database.ts +++ b/website/src/lib/__mocks__/wordlist-database.ts @@ -2,6 +2,7 @@ import { Types as T } from "@lingdocs/pashto-inflector"; import { dictionary } from "../dictionary"; import { baseSupermemo } from "../spaced-repetition"; import { refreshWordlist } from "./pouch-dbs"; +import { WordlistWord } from "../../types/dictionary-types"; let wordlistDb: { name: string, diff --git a/website/src/lib/audio-tools.ts b/website/src/lib/audio-tools.ts index ec71797..cc46528 100644 --- a/website/src/lib/audio-tools.ts +++ b/website/src/lib/audio-tools.ts @@ -10,6 +10,7 @@ import { addToAttachmentObject, removeAttachmentFromObject, } from "./wordlist-database"; +import { WordlistWord, WordlistWordWAttachments } from "../types/dictionary-types"; export function addAudioToWordlistWord(word: WordlistWord, file: File): WordlistWord { return { diff --git a/website/src/lib/dictionary.ts b/website/src/lib/dictionary.ts index 9853fa4..183f81f 100644 --- a/website/src/lib/dictionary.ts +++ b/website/src/lib/dictionary.ts @@ -21,6 +21,10 @@ import { fuzzifyPashto } from "./fuzzify-pashto/fuzzify-pashto"; import relevancy from "relevancy"; import { makeAWeeBitFuzzy } from "./wee-bit-fuzzy"; import { getTextOptions } from "./get-text-options"; +import { + DictionaryAPI, + State, +} from "../types/dictionary-types"; // const dictionaryBaseUrl = "https://storage.googleapis.com/lingdocs/"; const dictionaryUrl = `https://storage.googleapis.com/lingdocs/dictionary`; @@ -31,22 +35,6 @@ const dictionaryCollectionName = "dictionary3"; // const dictionaryDatabaseName = "dictdb.db"; export const pageSize = 35; -export type DictionaryAPI = { - initialize: () => Promise<{ - response: "loaded first time" | "loaded from saved", - dictionaryInfo: T.DictionaryInfo, - }>, - update: (updateComing: () => void) => Promise<{ - response: "no need for update" | "updated" | "unable to check", - dictionaryInfo: T.DictionaryInfo, - }>, - search: (state: State) => T.DictionaryEntry[], - exactPashtoSearch: (search: string) => T.DictionaryEntry[], - getNewWordsThisMonth: () => T.DictionaryEntry[], - findOneByTs: (ts: number) => T.DictionaryEntry | undefined, - findRelatedEntries: (entry: T.DictionaryEntry) => T.DictionaryEntry[], -} - const relevancySorter = new relevancy.Sorter(); const db = indexedDB.open('inPrivate'); diff --git a/website/src/lib/get-text-options.ts b/website/src/lib/get-text-options.ts index 3cc302e..f3e4d19 100644 --- a/website/src/lib/get-text-options.ts +++ b/website/src/lib/get-text-options.ts @@ -1,4 +1,7 @@ import { Types as T } from "@lingdocs/pashto-inflector"; +import { + State, +} from "../types/dictionary-types"; export function getTextOptions(state: State): T.TextOptions { return state.options.textOptionsRecord.textOptions; diff --git a/website/src/lib/image-tools.ts b/website/src/lib/image-tools.ts index 28855bc..1d1a994 100644 --- a/website/src/lib/image-tools.ts +++ b/website/src/lib/image-tools.ts @@ -2,6 +2,7 @@ import Resizer from "react-image-file-resizer"; import { addToAttachmentObject, removeAttachmentFromObject, } from "./wordlist-database"; +import { WordlistWord, WordlistWordWAttachments, AttachmentWithData } from "../types/dictionary-types"; const maxImgSize = { width: 1200, diff --git a/website/src/lib/local-storage.ts b/website/src/lib/local-storage.ts index 7461ef6..7ef3f01 100644 --- a/website/src/lib/local-storage.ts +++ b/website/src/lib/local-storage.ts @@ -7,6 +7,7 @@ */ import * as AT from "../types/account-types"; +import { Options } from "../types/dictionary-types"; export const optionsLocalStorageName = "options3"; export const userLocalStorageName = "user1"; diff --git a/website/src/lib/options-reducer.ts b/website/src/lib/options-reducer.ts index f25f0ee..6d8e698 100644 --- a/website/src/lib/options-reducer.ts +++ b/website/src/lib/options-reducer.ts @@ -1,5 +1,11 @@ import { Types as IT } from "@lingdocs/pashto-inflector"; import * as AT from "../types/account-types"; +import { + Options, + OptionsAction, + TextOptionsAction, + TextOptionsRecord, +} from "../types/dictionary-types"; export function optionsReducer(options: Options, action: OptionsAction): Options { if (action.type === "toggleLanguage") { diff --git a/website/src/lib/pouch-dbs.ts b/website/src/lib/pouch-dbs.ts index e2a3e49..26cc17e 100644 --- a/website/src/lib/pouch-dbs.ts +++ b/website/src/lib/pouch-dbs.ts @@ -1,6 +1,10 @@ import PouchDB from "pouchdb"; import * as AT from "../types/account-types"; import * as FT from "../types/functions-types"; +import { + WordlistWord, + WordlistWordDoc, +} from "../types/dictionary-types"; type LocalDbType = "submissions" | "wordlist" | "reviewTasks"; diff --git a/website/src/lib/search-all-inflections.ts b/website/src/lib/search-all-inflections.ts index e39face..7ae64ee 100644 --- a/website/src/lib/search-all-inflections.ts +++ b/website/src/lib/search-all-inflections.ts @@ -10,6 +10,9 @@ import { getVerbInfo, } from "@lingdocs/pashto-inflector"; import { isPashtoScript } from "./is-pashto"; +import { + InflectionSearchResult, +} from "../types/dictionary-types"; // 1st iteration: Brute force make every single conjugation and check all - 5300ms // 2nd iteration: Check if it makes a big difference to search via function - 5100ms diff --git a/website/src/lib/search-pile.ts b/website/src/lib/search-pile.ts index 9da6052..c228c28 100644 --- a/website/src/lib/search-pile.ts +++ b/website/src/lib/search-pile.ts @@ -14,6 +14,11 @@ import { isPluralInflectionSet, } from "@lingdocs/pashto-inflector"; import { personFromVerbBlockPos } from "@lingdocs/pashto-inflector"; +import { + InflectionName, + PluralInflectionName, + InflectionSearchResult, +} from "../types/dictionary-types"; const inflectionNames: { inflections: InflectionName[], plural: PluralInflectionName[] } = { inflections: ["plain", "1st", "2nd"], diff --git a/website/src/lib/spaced-repetition.ts b/website/src/lib/spaced-repetition.ts index a1141f2..1606580 100644 --- a/website/src/lib/spaced-repetition.ts +++ b/website/src/lib/spaced-repetition.ts @@ -15,6 +15,9 @@ import dayjs from "dayjs"; import { getMillisecondsPeriod, } from "./time-utils"; +import { + WordlistWord, +} from "../types/dictionary-types"; /* starting stage of review, based on Pimseleur intervals */ const warmupIntervals = [ diff --git a/website/src/lib/wordlist-database.ts b/website/src/lib/wordlist-database.ts index ac84996..a1506be 100644 --- a/website/src/lib/wordlist-database.ts +++ b/website/src/lib/wordlist-database.ts @@ -26,6 +26,12 @@ import { prepBase64, } from "./image-tools"; import { getMillisecondsPeriod } from "./time-utils"; +import { + WordlistWord, + AttachmentType, + Attachments, + AttachmentToPut, +} from "../types/dictionary-types"; export async function addToWordlist({ entry, notes }: { entry: T.DictionaryEntry, @@ -79,6 +85,7 @@ export async function getWordlistCsv(sortType: "alphabetical" | "time"): Promise [w.entry.p, w.entry.f, w.entry.c, w.entry.e] )); if (sortType === "alphabetical") { + // @ts-ignore forCsv.sort((a, b) => a[0].localeCompare(b[0], "ps")); } const csv = Papa.unparse(forCsv); diff --git a/website/src/screens/About.tsx b/website/src/screens/About.tsx index 18b3628..a04e16a 100644 --- a/website/src/screens/About.tsx +++ b/website/src/screens/About.tsx @@ -8,6 +8,7 @@ import { Helmet } from "react-helmet"; import dayjs from "dayjs"; +import { State } from "../types/dictionary-types"; const About = ({ state } : { state: State }) => (
diff --git a/website/src/screens/EntryEditor.tsx b/website/src/screens/EntryEditor.tsx index bb600bf..d6127a3 100644 --- a/website/src/screens/EntryEditor.tsx +++ b/website/src/screens/EntryEditor.tsx @@ -11,7 +11,6 @@ import classNames from "classnames"; import { Link } from "react-router-dom"; import { VPExplorer } from "@lingdocs/pashto-inflector"; import { entryFeeder } from "../lib/dictionary"; -import { DictionaryAPI } from "../lib/dictionary"; import { ConjugationViewer, InflectionsTable, @@ -30,6 +29,7 @@ import { import { Helmet } from "react-helmet"; import { TextOptions } from "@lingdocs/pashto-inflector/dist/types"; import * as AT from "../types/account-types"; +import { DictionaryAPI } from "../types/dictionary-types"; const textFields: {field: T.DictionaryEntryTextField, label: string}[] = [ { field: "p", label: "Pashto" }, diff --git a/website/src/screens/IsolatedEntry.tsx b/website/src/screens/IsolatedEntry.tsx index fab221d..739033d 100644 --- a/website/src/screens/IsolatedEntry.tsx +++ b/website/src/screens/IsolatedEntry.tsx @@ -35,8 +35,11 @@ import { Modal } from "react-bootstrap"; import { getTextOptions } from "../lib/get-text-options"; import { entryFeeder, - DictionaryAPI, } from "../lib/dictionary"; +import { + State, + DictionaryAPI, +} from "../types/dictionary-types"; function IsolatedEntry({ state, dictionary, isolateEntry }: { state: State, diff --git a/website/src/screens/Options.tsx b/website/src/screens/Options.tsx index 5393a20..85dda25 100644 --- a/website/src/screens/Options.tsx +++ b/website/src/screens/Options.tsx @@ -11,6 +11,15 @@ import { } from "@lingdocs/pashto-inflector"; import { Helmet } from "react-helmet"; import { wordlistEnabled } from "../lib/level-management"; +import { + State, + Options, + PTextSize, + SearchBarPosition, + Theme, + OptionsAction, + TextOptionsAction, +} from "../types/dictionary-types"; const fontSizeOptions: { label: string, diff --git a/website/src/screens/Results.tsx b/website/src/screens/Results.tsx index ba566db..4993397 100644 --- a/website/src/screens/Results.tsx +++ b/website/src/screens/Results.tsx @@ -21,9 +21,13 @@ import { Types as T, revertSpelling, } from "@lingdocs/pashto-inflector"; -import InflectionSearchResult from "../components/InflectionSearchResult"; +import InflectionSearchResultDisplay from "../components/InflectionSearchResult"; import { searchAllInflections } from "../lib/search-all-inflections"; import { getTextOptions } from "../lib/get-text-options"; +import { + State, + InflectionSearchResult, +} from "../types/dictionary-types"; const inflectionSearchIcon = "fas fa-search-plus"; @@ -125,7 +129,7 @@ function Results({ state, isolateEntry }: { />
{p.results.map((result: InflectionSearchResult, i) => ( - Promise<{ + response: "loaded first time" | "loaded from saved", + dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo, + }>, + update: (updateComing: () => void) => Promise<{ + response: "no need for update" | "updated" | "unable to check", + dictionaryInfo: import("@lingdocs/pashto-inflector").Types.DictionaryInfo, + }>, + search: (state: State) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[], + exactPashtoSearch: (search: string) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[], + getNewWordsThisMonth: () => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[], + findOneByTs: (ts: number) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry | undefined, + findRelatedEntries: (entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry) => import("@lingdocs/pashto-inflector").Types.DictionaryEntry[], +} + +export type WordlistWordBase = { + _id: string, + /* a backup copy of the full dictionary entry in case it gets deleted from the dictionary */ + entry: import("@lingdocs/pashto-inflector").Types.DictionaryEntry, + /* the notes/context provided by the user for the word in their wordlist */ + notes: string, + supermemo: import("supermemo").SuperMemoItem, + /* rep/stage of warmup stage before moving into supermemo mode */ + warmup: number | "done", + /* date due for review - ISO string */ + dueDate: number, +} + +export type WordlistAttachmentInfo = { + imgSize?: { height: number, width: number }, + _attachments: Attachments, +} + +export type WordlistWordWAttachments = WordlistWordBase & WordlistAttachmentInfo; + +export type WordlistWord = WordlistWordBase | WordlistWordWAttachments; + +export type Options = { + language: Language, + searchType: SearchType, + theme: Theme, + textOptionsRecord: TextOptionsRecord, + wordlistMode: WordlistMode, + wordlistReviewLanguage: Language, + wordlistReviewBadge: boolean, + searchBarPosition: SearchBarPosition, +} + +export type Language = "Pashto" | "English"; +export type SearchType = "alphabetical" | "fuzzy"; +export type Theme = "light" | "dark"; +export type PTextSize = "normal" | "larger" | "largest"; +export type Phonetics = "lingdocs" | "ipa" | "alalc" | "none"; +export type Dialect = "standard" | "peshawer" | "southern"; +export type SearchBarPosition = "top" | "bottom"; + +export type WordlistMode = "browse" | "review"; + +export type TextOptionsRecord = { + lastModified: import("./account-types").TimeStamp, + textOptions: import("@lingdocs/pashto-inflector").Types.TextOptions, +}; + +export type UserLevel = "basic" | "student" | "editor"; + +export type OptionsAction = { + type: "toggleSearchType", +} | { + type: "toggleLanguage", +} | { + type: "changeTheme", + payload: Theme, +} | { + type: "changeSearchBarPosition", + payload: SearchBarPosition, +} | { + type: "changeUserLevel", + payload: UserLevel, +} | { + type: "changeWordlistMode", + payload: WordlistMode, +} | { + type: "changeWordlistReviewLanguage", + payload: Language, +} | { + type: "changeWordlistReviewBadge", + payload: boolean, +} | { + type: "updateTextOptionsRecord", + payload: TextOptionsRecord, +}; + +export type TextOptionsAction = { + type: "changePTextSize", + payload: PTextSize, +} | { + type: "changeSpelling", + payload: import("@lingdocs/pashto-inflector").Types.Spelling, +} | { + type: "changePhonetics", + payload: "lingdocs" | "ipa" | "alalc" | "none", +} | { + type: "changeDialect", + payload: "standard" | "peshawer" | "southern", +} | { + type: "changeDiacritics", + payload: boolean, +}; + +export type AttachmentToPut = { + content_type: string, + data: string | Blob, +} + +export type AttachmentWithData = { + content_type: string, + digest: string, + data: string | Blob, +} + +export type AttachmentWOutData = { + content_type: string, + digest: string, + stub: true; +} + +export type Attachment = AttachmentToPut | AttachmentWithData | AttachmentWOutData +export type AttachmentType = "image" | "audio"; +export type Attachments = { + /* only allows one image and one audio attachment - max 2 values */ + [filename: string]: Attachment, +}; + +export type WordlistWordDoc = WordlistWord & { _rev: string, _id: string }; + +export type InflectionName = "plain" | "1st" | "2nd"; + +export type PluralInflectionName = "plural" | "2nd"; + +export type InflectionSearchResult = { + form: string[], + matches: { + ps: import("@lingdocs/pashto-inflector").Types.PsString, + pos: InflectionName[] | import("@lingdocs/pashto-inflector").Types.Person[] | null, + }[], +}; +