{"version":3,"sources":["webpack:///./src/components/dialogTools/DialogManager.tsx","webpack:///./src/components/NotificationManager.tsx","webpack:///./src/app/author/components/TopicFrame.tsx","webpack:///./src/utilities.ts","webpack:///./src/components/BusySpinner.tsx","webpack:///./src/hooks/useIsMounted.ts","webpack:///./src/formManager/FmForm.tsx","webpack:///./src/components/PopupMenu.tsx","webpack:///./src/domain/AppError.ts","webpack:///./src/http/http.ts","webpack:///./src/http/authenticated.ts","webpack:///./src/app/author/admin/requests/getUsers.ts","webpack:///./src/app/author/admin/requests/setAdminLevel.ts","webpack:///./src/components/ColumnContainer.tsx","webpack:///./src/components/buttons.tsx","webpack:///./src/components/dialogTools/ConfirmationDialogBase.tsx","webpack:///./src/components/SettingDescription.tsx","webpack:///./src/components/RowContainer.tsx","webpack:///./src/formManager/FmField.tsx","webpack:///./src/app/author/admin/components/ConfirmImpactfulActionDialog.tsx","webpack:///./src/app/author/admin/components/FilterUsersDialog.tsx","webpack:///./src/app/author/admin/components/SetExpiryDialog.tsx","webpack:///./src/app/author/admin/components/AdminUsersPage.tsx","webpack:///./src/app/author/admin/requests/disableUser.ts","webpack:///./src/app/author/admin/requests/setExpiry.ts","webpack:///./src/app/author/admin/requests/deleteUserGameData.ts","webpack:///./src/app/author/admin/requests/deleteUser.ts","webpack:///./src/app/author/admin/components/AdminTopic.tsx","webpack:///./src/components/PageIntro.tsx","webpack:///./src/components/SettingsContainer.tsx","webpack:///./src/components/Title.tsx","webpack:///./src/app/author/components/ChangeEmail.tsx","webpack:///./src/app/author/components/ChangePassword.tsx","webpack:///./src/components/dialogTools/InfoDialog.tsx","webpack:///./src/components/PageContainer.tsx","webpack:///./src/components/SettingHeader.tsx","webpack:///./src/app/author/components/CompleteRegistration.tsx","webpack:///./src/app/author/requests/completeRegistration.ts","webpack:///./src/components/Info.tsx","webpack:///./src/components/TellMeMore.tsx","webpack:///./src/app/author/requests/manageGameAbstracts.ts","webpack:///./src/app/author/requests/makeCacheValidatedRequest.ts","webpack:///./src/app/author/requests/createGame.ts","webpack:///./src/app/author/components/AddGameDialog.tsx","webpack:///./src/app/author/requests/getGame.ts","webpack:///./src/app/author/games/shared/components/ImportGameDialog.tsx","webpack:///./src/app/author/components/CreateGameButton.tsx","webpack:///./src/components/NotFound.tsx","webpack:///./src/app/author/components/FormToolbarEditorButtons.tsx","webpack:///./src/components/Hider.tsx","webpack:///./src/components/ToolbarTitle.tsx","webpack:///./src/formManager/useFormToolbar.ts","webpack:///./src/app/author/requests/saveGame.ts","webpack:///./src/components/ExplanatoryNote.tsx","webpack:///./src/domain/types.ts","webpack:///./src/components/HelpDialog.tsx","webpack:///./src/components/SettingSubheader.tsx","webpack:///./src/components/Emphasize.tsx","webpack:///./src/app/author/games/shared/components/EditNameGameTab.tsx","webpack:///./src/app/author/requests/getConfiguration.ts","webpack:///./src/domain/gameUrl.ts","webpack:///./src/app/author/requests/publishGame.ts","webpack:///./src/app/author/games/shared/components/EditPublishTab.tsx","webpack:///./src/components/Tip.tsx","webpack:///./src/domain/compute_types.ts","webpack:///./src/app/compute/components/ComputeRulesComponent.tsx","webpack:///./src/app/author/games/compute/components/ComputeEditRulesPrologueTab.tsx","webpack:///./src/app/author/games/shared/components/AutoScoringHelp.tsx","webpack:///./src/formManager/FmList.tsx","webpack:///./src/app/author/games/shared/components/Ladder.tsx","webpack:///./src/app/author/games/compute/components/ComputeEditScoringTab.tsx","webpack:///./src/app/author/games/compute/components/ComputeEditChallengesTab.tsx","webpack:///./src/app/author/games/shared/deriveLevelScores.ts","webpack:///./src/app/author/components/FormToolbarPublishButton.tsx","webpack:///./src/app/author/games/compute/components/ComputeEditPage.tsx","webpack:///./src/app/author/requests/manageUserGameSettings.tsx","webpack:///./src/app/author/games/spell/wordFinder.ts","webpack:///./src/app/author/games/spell/components/LetterButtonComponent.tsx","webpack:///./src/app/author/games/spell/components/LettersComponent.tsx","webpack:///./src/app/author/games/spell/components/AddWordsDialog.tsx","webpack:///./src/app/author/games/spell/components/VirtualizedWordList.tsx","webpack:///./src/hooks/useFreshState.ts","webpack:///./src/app/author/components/HiddenWordsPage.tsx","webpack:///./src/app/author/games/spell/components/AddGameWordsDialog.tsx","webpack:///./src/app/author/games/spell/components/WordList.tsx","webpack:///./src/app/author/games/spell/components/ReorderLettersDialog.tsx","webpack:///./src/app/author/games/spell/components/SpellEditPageChooseWordsTab.tsx","webpack:///./src/components/JustOkDialog.tsx","webpack:///./src/app/play/components/InputButtonComponent.tsx","webpack:///./src/app/spell/components/SpellRulesComponent.tsx","webpack:///./src/components/ConfirmationDialog.tsx","webpack:///./src/app/play/components/TopAppBarComponent.tsx","webpack:///./src/app/spell/components/SpellGameComponent.tsx","webpack:///./src/app/author/games/spell/components/SpellEditRulesPrologueTab.tsx","webpack:///./src/app/author/games/spell/components/SpellEditScoringTab.tsx","webpack:///./src/app/author/games/spell/components/SpellEditPage.tsx","webpack:///./src/app/twist/components/TwistRulesComponent.tsx","webpack:///./src/app/author/games/twist/components/TwistEditRulesPrologueTab.tsx","webpack:///./src/app/author/games/twist/components/TwistEditScoringTab.tsx","webpack:///./src/app/author/games/twist/components/EditChallengeDialog.tsx","webpack:///./src/app/author/games/twist/components/TwistChallengeTable.tsx","webpack:///./src/app/author/games/twist/components/BulkAddChallengesDialog.tsx","webpack:///./src/app/author/games/twist/components/TwistEditChallengesTab.tsx","webpack:///./src/app/author/games/twist/components/TwistEditPage.tsx","webpack:///./src/app/author/components/EditPage.tsx","webpack:///./src/app/author/requests/emptyTrash.ts","webpack:///./src/app/author/games/shared/components/makeEmptyTrashDialog.tsx","webpack:///./src/app/author/requests/deleteGame.ts","webpack:///./src/app/author/requests/trashGame.ts","webpack:///./src/app/author/requests/untrashGame.ts","webpack:///./src/app/author/components/GamesPage.tsx","webpack:///./src/app/author/requests/templateGame.ts","webpack:///./src/app/author/components/ImportGameButton.tsx","webpack:///./src/app/author/requests/manageLibraryAbstracts.ts","webpack:///./src/app/author/components/LibraryPage.tsx","webpack:///./src/app/author/components/TemplateSettings.tsx","webpack:///./src/app/author/components/TemplatesPage.tsx","webpack:///./src/app/author/components/GamesTopic.tsx","webpack:///./src/app/author/components/Login.tsx","webpack:///./src/app/author/components/Logoff.tsx","webpack:///./src/app/author/components/Privacy.tsx","webpack:///./src/app/author/requests/manageUserProfile.ts","webpack:///./src/app/author/components/Profile.tsx","webpack:///./src/app/author/components/Register.tsx","webpack:///./src/app/author/requests/registerNewUser.ts","webpack:///./src/app/author/components/ExtraWordsPage.tsx","webpack:///./src/app/author/components/SensitiveWordsPage.tsx","webpack:///./src/app/author/components/SettingsTopic.tsx","webpack:///./src/app/author/components/Subscription.tsx","webpack:///./src/app/author/requests/getSubscription.ts","webpack:///./src/app/author/components/Terms.tsx","webpack:///./src/components/MainNavigationMenuIcon.tsx","webpack:///./src/app/author/components/UserInfoDialog.tsx","webpack:///./src/components/VersionDialog.tsx","webpack:///./src/app/author/requests/getVersion.ts","webpack:///./src/app/author/components/TopAppBar.tsx","webpack:///./src/app/author/components/HomeComputeCard.tsx","webpack:///./src/app/author/components/HomeLibraryGamesCard.tsx","webpack:///./src/app/author/components/HomeSpellCard.tsx","webpack:///./src/app/author/components/HomeTwistCard.tsx","webpack:///./src/app/author/components/HomeYourGamesCard.tsx","webpack:///./src/app/author/components/Home.tsx","webpack:///./src/app/author/components/RouterTop.tsx","webpack:///./src/app/author/index.tsx"],"names":["dialogTable","Object","create","dialogIndex","dialogMethodsLocal","getDialogMethods","DialogManagerContext","Defer","props","renderer","document","getElementById","makeDialog","args","name","componentRenderer","undefined","toString","dialog","isOpen","register","notifyError","notifySuccess","notifyErrorTransient","notifySuccessTransient","nullCallback","NotifySnackbarComponent","open","setOpen","show","onShow","Snackbar","onClose","event","reason","anchorOrigin","vertical","horizontal","autoHideDuration","Alert","severity","message","useStyles","makeStyles","theme","createStyles","title","flexGrow","menuButton","marginRight","spacing","drawer","width","flexShrink","whiteSpace","drawerOpen","transition","transitions","easing","sharp","duration","enteringScreen","drawerClose","leavingScreen","overflowX","breakpoints","up","drawerContainer","overflowY","overFlowX","content","padding","marginLeft","toolbar","nested","paddingLeft","toolbarShift","mixins","TopicFrame","openDrawer","setOpenDrawer","classes","contentRef","contentTop","setContentTop","element","current","top","getBoundingClientRect","className","style","position","AppBar","color","elevation","ClickAwayListener","onClickAway","Drawer","paper","variant","onMouseEnter","onMouseLeave","onClick","Paper","square","List","ListItem","button","ListItemIcon","appIcon","ListItemText","primary","appIconMenuText","leftNav","height","ref","children","max","items","reduce","result","item","sum","a","n","makeSeparatedStringFromList","list","index","round","x","Math","serialIdCounter","serialId","pickout","pickLetters","source","length","letter","indexOf","intersection","lista","listb","wordb","includes","push","union","dict","forEach","keys","findDuplicates","word","shift","pluralize","count","shuffle","array","newArray","i","j","floor","random","join","shuffleString","text","split","Div","makeBusySpinnerComponent","promise","ms","alert","Promise","resolve","setTimeout","then","finally","close","catch","error","PaperComponent","disableBackdropClick","disableEscapeKeyDown","maxWidth","CircularProgress","busySpinnerInternal","busyPromise","r","useIsMounted","isMountedRef","FmFormContext","FmForm","debug","console","validators","fetchedFailed","setFetchedFailed","version","formDataForceRender","setFormDataForceRender","formDataRef","getFormData","setFormData","f","newData","Date","getTime","isSubmitting","setIsSubmitting","isDirty","setIsDirty","cleanVersionNumber","setCleanVersionNumber","cleanFormDataRef","setCleanVersion","changeChunks","inverseChangeChunks","redoChangeChunks","setFormDataInternal","mutator","isDerived","rv","draft","fmFormDataVersion","patches","inversePatches","fmFormRenderProps","setCleanFormData","formData","cleanFormData","s","submit","setDerivedFormData","undo","patchChunk","pop","redoChangeChunk","changes","inverseChanges","isUndoAvailable","redo","isRedoAvailable","registerValidator","validator","beforeunloadListener","preventDefault","returnValue","p","fetch","handler","trigger","beforeunloadListenerRef","isDirtyNow","suppressPrompt","window","addEventListener","removeEventListener","doSubmit","find","errorMessage","onSubmit","data","suppressSpinner","Grid","container","justify","when","Provider","value","e","Child","initialState","y","PopupMenu","state","setState","clickHandler","setClickHandler","handleClick","clientX","clientY","handleClose","pmProps","onContextMenu","cursor","Menu","keepMounted","anchorReference","anchorPosition","left","menuElements","AppError","Error","code","isExpected","super","this","AppErrorCode","post","path","body","method","JSON","stringify","request","response","parsedBody","json","ex","ok","statusText","http","Request","makeRequest","serverResponse","origin","errorCode","isExpectedError","payload","timestamp","makeRequestWithAuthentication","authIdToken","getAuthIdToken","convertStringToFilter","isAny","convertBooleanToFilter","isClear","admin","displayName","email","emailVerified","uid","disabled","setAdminLevel","display","flexWrap","flexDirection","ColumnContainer","justifyContent","center","alignItems","primaryButton","margin","secondaryButton","backgroundColor","strongGuidingButton","palette","secondary","main","mildGuidingButton","subtleButton","PrimaryButton","Button","type","autoFocus","SecondaryButton","StrongGuidingButton","MildGuidingButton","SubtleButton","ConfirmationDialogBase","okayText","handleCancel","history","listen","DialogTitle","id","DialogContent","dividers","DialogActions","fontSize","typography","body1","RowContainer","marginTop","marginBottom","toLabelFromVariableName","nameArray","upcase","toUpperCase","FmTextField","textFieldProps","labelText","placeholderText","valueProxyFuncs","onChange","label","fmFormContext","initialFocus","inputElement","focus","fieldData","get","isRequired","typeProp","inputType","newTextFieldProps","internalErrorMessage","setInternalErrorMessage","TextField","helperText","errorText","inputRef","fullWidth","autoComplete","placeholder","InputLabelProps","shrink","InputProps","readOnly","textInput","forceToLowerCase","currentTarget","toLowerCase","maxLength","Number","MAX_VALUE","mutate","draftFormData","oldFieldData","onBlur","setErrorMessage","positiveIntegers","FmFieldErrorCode","FmNumberField","onFocus","customErrorMessages","stringToValue","stringValue","valueToString","minValue","maxValue","hasFocus","setHasFocus","formDataValue","setStringValue","fieldValue","handleChange","UnderMin","OverMax","oldValue","inputProps","textAlign","target","test","FmSwitchField","switchFieldProps","FormControlLabel","control","Switch","checked","newFieldData","FmCheckboxField","checkboxFieldProps","Checkbox","indeterminate","currentValue","newValue","FmDiscreteSliderField","scale","marks","map","mark","Typography","gutterBottom","Slider","findIndex","mapIn","getAriaValueText","_value","step","valueLabelDisplay","_event","scaleValue","ConfirmImpactfulActionDialogInternal","openConfirmImpactfulActionDialog","makeConfirmImpactfulActionDialogComponent","dialogRenderProps","confirmationText","fmProps","isOkay","dialogTitleAndOkayText","dialogContentRenderer","filterUsersDialogInternal","makeFilterUsersDialogComponent","filter","setExpiryDialogInternal","makeSetExpiryDialogComponent","expiry","DatePicker","autoOk","clearable","format","d","MoreActions","MenuItem","key","tuid","disableUser","dr","openSetExpiryDialog","setExpiry","deleteUserGameData","deleteUser","IconButton","size","fetchHandler","users","incomplete","AdminUsersPage","RenderedFormChild","runSearch","getUsers","tableData","user","columns","field","render","rowData","alignContent","cellStyle","wordBreak","options","search","sorting","actions","icon","tooltip","isFreeAction","openFilterUsersDialog","appBar","zIndex","drawerPaper","overflow","Page","AdminTopic","settingsToolbar","setSettingsToolbar","usersToolbar","Toolbar","startIcon","page","setPage","Users","location","pathname","Settings","exact","routeProps","Divider","horizontalAlignment","Title","ChangeEmail","authUserInfo","UserContext","initialFormData","newEmail","currentUser","updateEmail","ChangePassword","password","updatePassword","InfoDialogBase","Dialog","PageContainer","CompleteRegistration","localStorage","getItem","auth","isSignInWithEmailLink","href","signInWithEmailLink","removeItem","tokens","completeRegistration","registrationToken","signInWithEmailAndPassword","_userCredential","openDialog","spellCheck","dialogInternal","makeComponent","TellMeMore","paddingTop","paddingBottom","minWidth","buttonText","registrationId","registrations","registerTimestampChangeHandler","gameAbstractsRecordCache","getAbstractsVersion","notifyHandlers","values","promiseCache","gameAbstractsRecord","getGameAbstractsRecord","gameAbstracts","updateAbstract","gameId","abstract","created","modified","findGameAbstractByName","trashed","getUniqueName","baseName","makeCacheValidatedRequest","record","ErrAbstractNotCurrent","createGame","deleted","gameType","subtitle","description","published","plays","template","insertAbstract","formControl","addGameDialogInternal","openAddGameDialog","makeAddGameDialog","gameName","templateGameRef","FormControl","InputLabel","Select","labelId","getGame","getWordsDialogInternal","makeImportGameDialogComponent","url","t2s","gameRef","gameRecord","direction","Box","m","CreateGameButton","NotFound","FormToolbarEditorButtons","Tooltip","hidden","unmount","ToolbarTitle","useFormToolbar","setFormToolbar","saveGame","gameSpec","playSpec","authorSpec","getGameTypeLabel","getGameTypeIcon","gameTypeHasAnswers","AutoScoringMethod","helpPages","home","helpItems","helpInstanceId","useHelp","helpElement","isActive","myHelpInstanceIdRef","makeHelpDialogComponent","helpKey","largestActiveId","instanceIdText","instanceId","getHighestActiveHelpKey","navHelp","EditNameGameTab","isTemplateGame","prevProps","nextProps","answerKey","SaveUndoRedoHelp","getConfiguration","getConfigurationInternal","gameUrlPattern","recaptchaSiteKey","getGameUrl","configuration","replace","publishGame","handlePublish","setIsPublished","EditPublishTab","gameUrl","setGameUrl","navigator","clipboard","writeText","isPublished","tip","background","light","Tip","Op","getOpChar","op","Add","Mul","Sub","solve","c","lhs","rhs","validSingle","RegExp","String","raw","validRange","hyphenWithWhitespace","whitespace","compile","t","trim","convertOperandToNumber","start","end","ts","createChallenges","od","challenges","lhsRange","loperand","rhsRange","roperand","challenge","ComputeRulesComponent","gameInfo","rulesPrologue","rulesPrologueComponent","Container","opList","add","addChallenges","opLabel","opCount","sub","subChallenges","mul","mulChallenges","div","divChallenges","opsText","challengeCount","highestLevel","score","maxPoints","timeLimit","mustSolve","levels","level","ComputeEditRulesPrologueTab","multiline","rows","AutoScoringHelp","FmList","sortComparer","itemAction","minItems","maxItems","unsortedValues","sort","b","renderItems","wrappedValue","wrappedValues","fmListRenderProps","sortedIndex","setFormDataValue","action","splice","showAddButton","addButtonLabel","onDragEnd","provided","destination","reorder","droppableId","providedDroppable","snapshot","innerRef","droppableProps","renderItem","draggableId","isDragDisabled","draggableProps","dragHandleProps","tile","border","paddingRight","nameField","scoreField","slider","Ladder","highScore","autoScoring","previousNameIndex","highestRenderedIdRef","Slow","Medium","Fast","itemActionRenderProps","nameCandidate","slice","valuesLength","scoreAbove","scoreBelow","highestRenderedId","LevelTile","setValue","remove","addBelow","scoreDisabled","deleteDisabled","firstTile","animate","customErrorMessagesMax","Grow","in","transformOrigin","timeout","fillOpacity","ComputeEditScoringTab","autoScoringMethod","divider","ComputeEditChallengesTab","OpWidget","opEnabled","domain","enableDomain","enabled","setDomain","OperandRangeField","rangeText","setRangeText","memokey_deriveLevelScores","clearLevelScoresCache","deriveLevelScores","dependencies","memokey","highIndex","deltaLinear","secondScore","deltaHard","penultimateScore","delta","FormToolbarPublishButton","draftDerivedFormData","tabNames","tabNavNames","buildPlaySpec","ComputeEditPage","getGameFromAbstract","gameAbstract","initialLevels","commonFormData","computePlaySpec","setToolbar","displayTabIndex","setDisplayTabIndex","justifySelf","showAnswerKey","userGameSettings","getUserGameSettings","settings","extraWords","hiddenWords","includeSensitiveWords","saveUserGameSettings","tempUserGameSettings","assign","sensitiveWordsMapCache","extraWordsCache","includeSensitiveWordsCache","snipDictionaryCache","getCurrentSnipDictionary","dictionaryList","dictionaryWords","wordCollections","performance","now","sensitiveWords","wordCount","collection","log","snipDictionary","dictionary","letters","last","snip","snipString","makeSnipDictionary","hiddenWordsMapCache","hiddenWordsCache","allLetters","findWords","requiredLetters","optionalLetters","minimumWordLength","maxWordCount","snips","o","rlCount","b2","clips","pattern","included","clip","makeSnips","hiddenWordsMap","words","foundWords","wordList","addWords","LetterButtonComponent","LettersComponent","requiredLetter","openAddWordsDialog","makeAddWordsDialogComponent","submitHandler","reject","dups","bonus","tabName","info","getItemKey","VirtualizedWordList","rowFunc","borderRadius","removeWord","rowRenderer","itemCount","itemSize","itemKey","itemData","useFreshState","currentState","_reactState","setReactState","initialValue","validateWords","theseWords","theseName","otherWords","otherName","alreadyFound","inDictionary","isWordInDictionary","HiddenWordsPage","getFilter","setFilter","filteredWords","filteredWord","endAdornment","InputAdornment","ftext","delIndex","makeAddGameWordsDialogComponent","mismatched","rls","ols","rl","l","getWordsThatDoNotMatchCriteria","maxHeight","GearIcon","WordSource","Tile","isLongestWord","isPangram","isSpecialWord","toggleSpecial","System","disableFocusListener","WordList","greatestLength","isSpecial","openAddGameWordsDialog","wordsToAddToExtraWordsList","reorderLettersDialogInternal","makeReorderLettersDialogComponent","SpellEditPageChooseWordsTab","foundWordsLengthRef","showDisappearingLettersHint","setShowDisappearingLettersHint","wordListWords","wordListAllLetters","wordListActions","foundWord","deduped","resultLetters","resultLetter","openReorderLettersDialog","keyDownHandler","stopPropagation","JustOkDialog","inlineJustOkDialogInternal","openJustOkDialog","makeJustOkDialog","SpellRulesComponent","RequiredLettersInfoComponent","canReuseLetters","minLength","pangramCount","answers","makeSeparatedElementStringFromList","inlineConfirmationDialogInternal","openConfirmationDialog","DispatchType","getCanReuseLetters","answer","Array","from","letterCount","getPangramCount","answerLetters","answerLetterCount","pangrams","getMinLength","SpellEditRulesPrologueTab","BonusHelp","SpellEditScoringTab","pangramBonus","longestWordBonus","specialWordBonus","SpellEditPage","memokey_deriveAnswers","deriveAnswers","spellPlaySpec","spellAuthorSpec","TwistRulesComponent","extraLetterChallengeCount","fillin","fixed","caseSensitive","TwistEditRulesPrologueTab","TwistEditScoringTab","editChallengeDialogInternal","openEditChallengeDialog","makeEditChallengeDialogComponent","otherSolutions","solutions","solution","clue","sl","asterisks","makeDefaultFixedString","getMinimalFillin","fixedLetter","fillinLetter","tileField","TwistChallengeTable","originalIndex","newIndex","moving","ChallengeTile","getBulkAddChallengesDialogInternal","makeBulkAddChallengesDialogComponent","currentChallenges","lines","bulkExports","line","be","TwistEditChallengesTab","openBulkAddChallengesDialog","newChallenges","bulkExport","TwistEditPage","twistPlaySpec","EditPage","setGameAbstract","emptyTrash","abstracts","deleteTrashedAbstracts","makeEmptyTrashDialog","trashCount","deleteGame","deleteAbstract","trashGame","trashAbstract","untrashGame","untrashAbstract","templateGame","isTemplate","gameAbstractsVersion","gameTypeFilter","GamesPage","showDeleted","setShowDeleted","publish","numtrashed","trashSwitch","selectGameType","customFilterAndSearch","searchText","match","defaultSort","customSort","a1","a2","toLocaleString","localization","emptyDataSourceMessage","openByName","tokenIndex","token","VMenu","ImportGameButton","libraryAbstractsRecordCache","libraryAbstractsRecord","getLibraryAbstractsRecord","LibraryPage","TemplateSettings","templateName","setTemplateName","templateId","setTemplateId","abstractsRecord","gameTypeLabel","TemplatesPage","GamesTopic","editorToolbar","setEditorToolbar","templatesToolbar","setTemplatesToolbar","gamesToolbar","openImportGameDialog","Games","locpath","Templates","Library","startsWith","Edit","Login","setPersistence","Auth","Persistence","LOCAL","redirectPath","sendPasswordResetEmail","Logoff","loggedOff","setLoggedOff","logoffError","setLogoffError","Link","signOut","Privacy","useUserProfile","userProfile","setUserProfile","initials","getUserProfile","gUserProfile","Profile","saveUserProfile","draftUserProfile","recaptchaValue","Register","config","setItem","registerNewUser","recaptcha","forceUpdate","setForceUpdate","CP_RECAPTCHAReady","newDiv","grecaptcha","sitekey","callback","RegistrationSubmitted","ExtraWordsPage","SensitiveWordsPage","SettingsTopic","extraWordsToolbar","setExtraWordsToolbar","hiddenWordsToolbar","setHiddenWordsToolbar","sensitiveWordsToolbar","setSensitiveWordsToolbar","Hidden","Extra","Sensitive","root","textField","Subscription","getSubscription","Terms","MainNavigationMenuIcon","edge","userInfoDialogInternal","makeUserInfoDialog","userProfileData","Avatar","alt","Version","versionItems","setVersionItems","getVersion","reponse","TopAppBar","getOpenDrawer","ignoreExternalClickOnce","setIgnoreExternalClickOnce","toggleDrawer","setToggleNavMenu","openHelpDialog","openUserInfoDialog","onKeyDown","isAdmin","minHeight","header","media","backgroundSize","avatar","red","HomeComputeCard","Card","CardHeader","subheader","CardActions","CardMedia","image","CardContent","component","HomeLibraryGamesCard","HomeSpellCard","HomeTwistCard","HomeYourGamesCard","authPromise","lastAuthIdTokenRefresh","getIdToken","createMuiTheme","identityTokens","CP_IDENTITY","apiKey","authDomain","CssBaseline","setShow","setMessage","setSeverity","setCallback","setAutoHideDuration","notify","utils","stateIndex","setStateIndex","dialogOpen","dialogMethods","dialogTableItem","setUid","setAdmin","toggleNavMenu","onAuthStateChanged","adminData","getIdTokenResult","claims","parseInt","getToggleNavMenu"],"mappings":"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","file":"main.c3a497f916c0c879c651.js","sourcesContent":["import * as React from \"react\";\nimport { createContext, useState } from \"react\";\nimport * as ReactDOM from \"react-dom\";\n\nexport interface DialogResponse {\n isOkay: boolean;\n result: TResult;\n}\n\ninterface DialogComponentRenderer {\n (renderProps: {\n close: (isOkay: boolean, result: TResult) => void;\n props: TProps;\n }): JSX.Element;\n}\nexport interface Dialog {\n name: string;\n componentRenderer: DialogComponentRenderer;\n isOpen: boolean;\n result?: TResult;\n resolve?: (result: DialogResponse) => void;\n}\n\ninterface DialogManagerProps {}\ninterface DialogMethods {\n open: (\n dialog: Dialog,\n props?: TProps\n ) => Promise>;\n openByName: (\n dialogName: string,\n props?: TProps\n ) => Promise>;\n}\n\nconst dialogTable: Record<\n string,\n { dialog: Dialog; props?: unknown }\n> = Object.create(null);\nlet dialogIndex = 0;\n\nconst register = (args: {\n name: string;\n componentRenderer: DialogComponentRenderer;\n}) => {\n const { componentRenderer } = args;\n let name = args.name;\n if (name === undefined) {\n // auto-assign name\n dialogIndex++;\n name = \"__autonamed__\" + dialogIndex.toString();\n }\n const dialog = { name, componentRenderer, isOpen: false };\n dialogTable[name] = { dialog };\n return dialog;\n};\n\nlet dialogMethodsLocal: DialogMethods;\nexport const getDialogMethods = () => dialogMethodsLocal;\n\nexport const DialogManagerContext = createContext(null);\n\nexport const DialogManager: React.FunctionComponent = (\n props\n) => {\n const [stateIndex, setStateIndex] = useState(0);\n\n const dialogOpen = (\n dialog: Dialog,\n props: TProps\n ) => {\n dialog.isOpen = true;\n dialogTable[dialog.name].props = props;\n setStateIndex(stateIndex + 1);\n return new Promise>((resolve, reject) => {\n dialog.resolve = resolve;\n });\n };\n const dialogMethods: DialogMethods = {\n open: dialogOpen,\n openByName: (name: string, props: TProps) => {\n return dialogOpen(dialogTable[name].dialog, props);\n },\n };\n dialogMethodsLocal = dialogMethods;\n return (\n \n {Object.values(dialogTable).map((dialogTableItem, index) => {\n if (dialogTableItem.dialog.isOpen) {\n const close = (isOkay: boolean, result: TResult) => {\n dialogTableItem.dialog.isOpen = false;\n dialogTableItem.dialog.resolve({ isOkay, result });\n setStateIndex(stateIndex + 1);\n };\n return (\n \n \n dialogTableItem.dialog.componentRenderer({\n close,\n props: dialogTableItem.props,\n })\n }\n />\n \n );\n }\n return null;\n })}\n <>{props.children}\n \n );\n};\n\n// Defer so that hooks are called when dialog is rendered as a child,\n// not as part of parent render.\n// Otherwise the parent calls different hooks at different times.\nconst Defer = (props: { renderer: () => JSX.Element }) => {\n return ReactDOM.createPortal(\n props.renderer(),\n document.getElementById(\"dialog\")\n );\n};\n\nexport const makeDialog = (args: {\n name?: string;\n componentRenderer: DialogComponentRenderer;\n}) => {\n const { name, componentRenderer } = args;\n return register({\n name,\n componentRenderer,\n });\n};\n","import Snackbar from \"@material-ui/core/Snackbar\";\nimport Alert from \"@material-ui/lab/Alert\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\ntype Severity = \"error\" | \"info\" | \"success\" | \"warning\";\n\nexport let notifyError: (message: string, callback?: () => void) => void;\n\nexport let notifySuccess: (message: string, callback?: () => void) => void;\n\nexport let notifyErrorTransient: (\n message: string,\n callback?: () => void\n) => void;\n\nexport let notifySuccessTransient: (\n message: string,\n callback?: () => void\n) => void;\n\nconst nullCallback = () => {};\n\ninterface NotificationManagerProps {}\nexport const NotificationManager: React.FunctionComponent = (\n props\n) => {\n const [show, setShow] = useState(false);\n const [message, setMessage] = useState(\"\");\n const [severity, setSeverity] = useState(undefined);\n const [callback, setCallback] = useState<() => void>(undefined);\n const [autoHideDuration, setAutoHideDuration] = useState(0);\n const notify = (\n message: string,\n severity: Severity,\n callback: () => void,\n autoHideDuration: number\n ) => {\n if (typeof message !== \"string\") {\n // try message.message\n if (typeof (message as any)?.message !== \"string\") {\n console.error(\"notify expected string, got \" + typeof message, message);\n setMessage(\"Error detected\");\n }\n message = (message as any).message;\n }\n setMessage(message);\n setCallback(callback ?? nullCallback);\n setSeverity(severity);\n setAutoHideDuration(autoHideDuration);\n setShow(true);\n };\n\n notifyError = (message: string, callback?: () => void) =>\n notify(message, \"error\", callback, 0);\n notifySuccess = (message: string, callback?: () => void) =>\n notify(message, \"success\", callback, 0);\n notifyErrorTransient = (message: string, callback?: () => void) =>\n notify(message, \"error\", callback, 2000);\n notifySuccessTransient = (message: string, callback?: () => void) =>\n notify(message, \"success\", callback, 2000);\n\n return (\n setShow(false)}\n onClose={callback}\n autoHideDuration={autoHideDuration}\n />\n );\n};\n\nfunction NotifySnackbarComponent(props: {\n message: JSX.Element | string;\n show: boolean;\n onShow: () => void;\n severity: Severity;\n onClose: () => void;\n autoHideDuration: number;\n}) {\n const [open, setOpen] = React.useState(false);\n\n const handleClose = (event?: React.SyntheticEvent, reason?: string) => {\n setOpen(false);\n props.onClose && props.onClose();\n };\n\n React.useEffect(() => {\n if (props.show) {\n setOpen(true);\n props.onShow();\n }\n });\n return (\n \n {props.message}\n \n );\n}\n","import AppBar from \"@material-ui/core/AppBar\";\nimport ClickAwayListener from \"@material-ui/core/ClickAwayListener\";\nimport Drawer from \"@material-ui/core/Drawer\";\nimport List from \"@material-ui/core/List\";\nimport ListItem from \"@material-ui/core/ListItem\";\nimport ListItemIcon from \"@material-ui/core/ListItemIcon\";\nimport ListItemText from \"@material-ui/core/ListItemText\";\nimport Paper from \"@material-ui/core/Paper\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport clsx from \"clsx\";\nimport * as React from \"react\";\nimport { useState, useRef, useEffect } from \"react\";\n\nconst drawerWidth = 240;\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n drawer: {\n width: drawerWidth,\n flexShrink: 0,\n whiteSpace: \"nowrap\",\n },\n drawerOpen: {\n width: drawerWidth,\n\n transition: theme.transitions.create(\"width\", {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.enteringScreen,\n }),\n },\n drawerClose: {\n transition: theme.transitions.create(\"width\", {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.leavingScreen,\n }),\n overflowX: \"hidden\",\n width: theme.spacing(6) + 1,\n [theme.breakpoints.up(\"sm\")]: {\n width: theme.spacing(7) + 1,\n },\n },\n drawerContainer: {\n overflowY: \"auto\",\n overFlowX: \"hidden\",\n },\n content: {\n padding: theme.spacing(3),\n marginLeft: theme.spacing(6) + 1,\n [theme.breakpoints.up(\"sm\")]: {\n marginLeft: theme.spacing(7) + 1,\n },\n },\n toolbar: {\n // padding: theme.spacing(3),\n marginLeft: theme.spacing(6) + 1,\n [theme.breakpoints.up(\"sm\")]: {\n marginLeft: theme.spacing(7) + 1,\n },\n },\n nested: {\n paddingLeft: theme.spacing(4),\n },\n // Loads information about the app bar, including app bar height\n toolbarShift: theme.mixins.toolbar,\n });\n});\n\nexport interface TopicFrameProps {\n appIcon: JSX.Element;\n appIconMenuText: string;\n leftNav: JSX.Element;\n toolbar: JSX.Element;\n}\n\nexport const TopicFrame: React.FunctionComponent = (props) => {\n const [openDrawer, setOpenDrawer] = useState(false);\n const classes = useStyles();\n\n const toggleDrawer = () => {\n setOpenDrawer(!openDrawer);\n };\n\n const contentRef = useRef(null);\n const [contentTop, setContentTop] = useState(0);\n\n useEffect(() => {\n const element = contentRef.current;\n if (element) {\n const top = element.getBoundingClientRect().top;\n if (top !== contentTop) {\n setContentTop(top);\n }\n }\n });\n return (\n <>\n
\n \n
{props.toolbar}
\n
\n
\n {\n setOpenDrawer(false);\n }}\n >\n setOpenDrawer(true)}\n onMouseLeave={() => setOpenDrawer(false)}\n onClick={() => setOpenDrawer(false)}\n >\n
\n <>\n \n \n \n {props.appIcon}\n \n \n \n \n {props.leftNav}\n \n \n \n \n {props.children}\n
\n \n );\n};\n","export const min = (items: T[]): T => {\n // undefined is min\n return items.reduce((result, item) => {\n if (item === undefined || result === undefined) return undefined;\n if (item < result) return item;\n return result;\n }, items[0]);\n};\n\nexport const max = (items: T[]): T => {\n // undefined is max\n return items.reduce((result, item) => {\n if (item === undefined || result === undefined) return undefined;\n if (item > result) return item;\n return result;\n }, items[0]);\n};\n\nexport const sum = (a: number[]) => a.reduce((sum, n) => (sum += n), 0);\n\nexport const makeSeparatedStringFromList = (list: string[]): string => {\n if (list === undefined) return undefined;\n return list.reduce((result, item, index) => {\n if (index === 0) return item;\n return result + \", \" + item;\n }, \"\");\n};\n\nexport const round = (x: number) => Math.round(x);\n\nexport function uuidv4() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n var r = (Math.random() * 16) | 0,\n v = c == \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\nlet serialIdCounter = -1;\nexport const serialId = () => ++serialIdCounter;\n\n// pickout removes pickLetters from the source.\n// Any letter in pickLetters is removed from the source.\nexport const pickout = (pickLetters: string, source: string) => {\n if (source == null || source.length === 0) return source;\n return [...(source ?? [])].reduce((result, letter) => {\n if (pickLetters.indexOf(letter) >= 0) return result;\n return result + letter;\n }, \"\");\n};\n\nexport const delay = (promise: Promise, ms: number) => {\n return new Promise((resolve) => setTimeout(resolve, ms)).then(() => promise);\n};\n\nexport const delay2 = (ms: number) => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\n// Assumes no duplicates in either list\n// Merges without additional duplication\nexport const mergeWordLists = (lista: string[], listb: string[]) => {\n lista = lista ?? [];\n listb = listb ?? [];\n return listb.reduce((result, wordb) => {\n if (lista.includes(wordb)) return result;\n result.push(wordb);\n return result;\n }, lista);\n};\n\n// Assumes no duplicates in either list\nexport const intersection = (lista: string[], listb: string[]) => {\n lista = lista ?? [];\n listb = listb ?? [];\n return listb.reduce((result, wordb) => {\n if (lista.includes(wordb)) {\n result.push(wordb);\n return result;\n }\n return result;\n }, [] as string[]);\n};\n\n// eliminates duplicates\nexport const union = (lista: string[], listb: string[]) => {\n lista = lista ?? [];\n listb = listb ?? [];\n const dict: Record = Object.create(null);\n lista.forEach((item) => (dict[item] = true));\n listb.forEach((item) => (dict[item] = true));\n return Object.keys(dict);\n};\n\n// Much faster to use loops with indices\n// Returns list of duplicates\nexport const findDuplicates = (list: string[]) => {\n const lista = [...(list ?? [])];\n return list.reduce((result, word) => {\n lista.shift();\n if (lista.includes(word)) {\n result.push(word);\n return result;\n }\n return result;\n }, []);\n};\n\nexport const pluralize = (count: number, word: string) => {\n if (count === 1) return `${count} ${word}`;\n return `${count} ${word}s`;\n};\n\nexport const shuffle = (array: Array) => {\n const newArray = [...array];\n let count = 0;\n while (true) {\n for (let i = newArray.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [newArray[i], newArray[j]] = [newArray[j], newArray[i]];\n }\n // Don't return the items in the same order.\n // Stop at 10 tries since some letter combinations are problematic (such as a string consisting of exactly 2 of the same letter)\n count++;\n if (\n newArray.length < 2 ||\n newArray.join(\"\") !== array.join(\"\") ||\n count === 10\n )\n return newArray;\n }\n};\n\nexport const shuffleString = (text: string) => {\n return shuffle(text.split(\"\")).join(\"\");\n};\n\n// shuffleArray shuffles an array of any type\n// It currently doesn't check to insure a change took place\nexport const shuffleArray = (array: Array) => {\n const newArray = [...array];\n for (let i = newArray.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [newArray[i], newArray[j]] = [newArray[j], newArray[i]];\n }\n return newArray;\n};\n\n// isAnagramOf returns true if a is an anagram of b.\nexport const isAnagramOf = (a: string, b: string) => {\n if (a == null || b == null) return false;\n return [...a].sort().join(\"\") === [...b].sort().join(\"\");\n};\n","import CircularProgress from \"@material-ui/core/CircularProgress\";\nimport MuiDialog from \"@material-ui/core/Dialog\";\nimport * as React from \"react\";\nimport { delay } from \"../utilities\";\nimport {\n getDialogMethods,\n makeDialog,\n Dialog,\n} from \"./dialogTools/DialogManager\";\n\nexport interface BusySpinnerProps {\n promise: Promise;\n}\n\nconst Div: React.FunctionComponent = (props) => {\n return
{props.children}
;\n};\n\nconst makeBusySpinnerComponent = () => {\n const dialog = makeDialog({\n name: \"BusySpinner\",\n componentRenderer: (props) => {\n if (props.props.promise === undefined) {\n alert(\"please supply a promise to BusySpinner\");\n }\n // Delay so user does not see flash for fast operations\n delay(props.props.promise, 250).finally(() => {\n props.props.promise\n .then((result) => {\n return props.close(true, result);\n })\n .catch((error) => {\n props.close(true, props.props.promise);\n throw error;\n });\n });\n return (\n \n \n \n );\n },\n });\n return dialog;\n};\n\nlet busySpinnerInternal: Dialog;\nconst openBusySpinner = (props: BusySpinnerProps) => {\n if (!busySpinnerInternal) {\n busySpinnerInternal = makeBusySpinnerComponent();\n }\n return getDialogMethods().open(\n busySpinnerInternal as Dialog,\n props\n );\n};\n\n// busyPromise returns the inner promise, which makes it convenient to call.\n// Issue: the user is forced to wait a small bit so that the spinner doesn't flash.\nexport const busyPromise = (promise: Promise) => {\n const dialogMethods = getDialogMethods();\n return openBusySpinner({ promise }).then((r) => {\n return r.result as T;\n });\n};\n","import { useRef, useEffect } from \"react\";\n\nexport const useIsMounted = () => {\n const isMountedRef = useRef(true);\n useEffect(() => {\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n return isMountedRef;\n};\n","import Grid from \"@material-ui/core/Grid\";\nimport produce, { applyPatches, Draft, Patch } from \"immer\";\nimport * as React from \"react\";\nimport { createContext, useEffect, useRef, useState } from \"react\";\nimport { Prompt } from \"react-router-dom\";\nimport { busyPromise } from \"../components/BusySpinner\";\nimport { notifyError } from \"../components/NotificationManager\";\nimport { useIsMounted } from \"../hooks/useIsMounted\";\n\nexport interface FmFormRenderProps {\n isDirty: boolean;\n setCleanFormData: (formData: TFormData) => void;\n isSubmitting: boolean;\n setIsSubmitting: (isSubmitting: boolean) => void;\n formData: TFormData;\n cleanFormData: TFormData;\n submit: () => Promise;\n setFormData: (\n mutator: (formData: Draft) => TFormData | void\n ) => TFormData;\n setDerivedFormData: (\n mutator: (formData: Draft) => TFormData | void\n ) => TFormData;\n undo: () => void;\n isUndoAvailable: boolean;\n redo: () => void;\n isRedoAvailable: boolean;\n registerValidator: (validator: Validator) => void;\n}\n\nexport interface FmFormProps {\n fetch: { handler: () => Promise; trigger?: () => unknown };\n onSubmit: (\n fmFormRenderProps: FmFormRenderProps\n ) => Promise;\n name?: string;\n suppressSpinner?: boolean;\n // Suppress the prompt the blocks navigation\n suppressPrompt?: boolean;\n debug?: boolean;\n}\n\nexport interface Validator {\n (formData: TFormData): string; // returns undefined if there is no error, otherwise the error message\n}\n\nexport const FmFormContext = createContext>(null);\n\ntype TypeFormData = {\n [K in \"fmFormDataVersion\"]: number;\n};\n\nexport const FmForm = (\n props: FmFormProps & {\n children?: (fmProps: FmFormRenderProps) => React.ReactNode;\n }\n): React.ReactElement | null => {\n if (props.debug) console.debug(\"FmForm rendering\");\n const validators = useRef[]>([]);\n\n const [fetchedFailed, setFetchedFailed] = useState(false);\n const version = useRef(0);\n const [formDataForceRender, setFormDataForceRender] = useState(0);\n const formDataRef = useRef(undefined);\n // Get formData via function call so as not to get stale via closure\n const getFormData = () => formDataRef.current;\n const setFormData = (f: () => TFormData) => {\n const newData = f();\n if (newData === formDataRef.current) return;\n formDataRef.current = newData;\n // Don't rely on knowing prev state.\n // It might be stale due to closure AND that we use React.memo for some components.\n setFormDataForceRender(new Date().getTime());\n };\n\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isDirty, setIsDirty] = useState(undefined);\n const [cleanVersionNumber, setCleanVersionNumber] = useState(version.current);\n const cleanFormDataRef = useRef(undefined);\n const getCleanFormData = () => cleanFormDataRef.current;\n const setCleanVersion = (version: number) => {\n setCleanVersionNumber(version);\n setIsDirty(false);\n cleanFormDataRef.current = formDataRef.current;\n };\n interface PatchChunk {\n patches: Patch[];\n isDerived?: boolean;\n }\n const changeChunks = useRef([]);\n const inverseChangeChunks = useRef([]);\n const redoChangeChunks = useRef<\n { changes: PatchChunk; inverseChanges: PatchChunk }[]\n >([]);\n\n const fmSetCleanFormData = (formData: TFormData) => {\n setCleanVersion(formData.fmFormDataVersion);\n };\n\n const undo = () => {\n if (inverseChangeChunks.current.length > 0) {\n const patchChunk = inverseChangeChunks.current.pop();\n const redoChangeChunk = {\n changes: changeChunks.current.pop(),\n inverseChanges: patchChunk,\n };\n redoChangeChunks.current.push(redoChangeChunk);\n setFormData(() => {\n return applyPatches(getFormData(), patchChunk.patches);\n });\n }\n };\n\n const redo = () => {\n if (redoChangeChunks.current.length > 0) {\n const redoChangeChunk = redoChangeChunks.current.pop();\n changeChunks.current.push(redoChangeChunk.changes);\n inverseChangeChunks.current.push(redoChangeChunk.inverseChanges);\n setFormData(() =>\n applyPatches(getFormData(), redoChangeChunk.changes.patches)\n );\n }\n };\n\n const setFormDataInternal = (\n mutator: (draftFormData: Draft) => TFormData,\n isDerived = false\n ) => {\n // cannot redo once state is changed (except when doing undo/redo)\n if (!isDerived) redoChangeChunks.current = [];\n const rv = produce(\n getFormData(),\n (draft) => {\n if (!isDerived) draft.fmFormDataVersion = ++version.current;\n mutator(draft);\n return;\n },\n (patches, inversePatches) => {\n if (isDerived) return;\n changeChunks.current.push({ patches, isDerived });\n inverseChangeChunks.current.push({\n patches: inversePatches,\n isDerived,\n });\n }\n ) as TFormData;\n setFormData(() => rv);\n return rv;\n };\n\n const setIsSubmittingInternal = (s: boolean) => {\n setIsSubmitting(s);\n };\n\n const fmFormRenderProps: FmFormRenderProps = {\n isDirty,\n setCleanFormData: fmSetCleanFormData,\n formData: getFormData(),\n cleanFormData: getCleanFormData(),\n setIsSubmitting: setIsSubmittingInternal,\n isSubmitting,\n submit: undefined as any,\n setFormData: setFormDataInternal,\n setDerivedFormData: (mutator: (formData: Draft) => TFormData) =>\n setFormDataInternal(mutator, true),\n undo,\n isUndoAvailable: inverseChangeChunks.current.length > 0,\n redo,\n isRedoAvailable: redoChangeChunks.current.length > 0,\n registerValidator: (validator: Validator) =>\n validators.current.push(validator),\n };\n\n const isMountedRef = useIsMounted();\n\n // Re-fetch if the fetch trigger changed\n useEffect(() => {\n const p = props.fetch\n .handler()\n .then((formData) => {\n setFormData(() => formData);\n setCleanVersion(formData.fmFormDataVersion);\n setFetchedFailed(false);\n })\n .catch((error) => {\n setFetchedFailed(true);\n notifyError(error);\n throw error;\n });\n busyPromise(p); // show spinner\n }, [props.fetch.trigger && props.fetch.trigger()]);\n\n function beforeunloadListener(event: BeforeUnloadEvent) {\n event.preventDefault();\n event.returnValue = \"You may lose changes if you proceed...\";\n }\n\n const beforeunloadListenerRef = useRef<(event: BeforeUnloadEvent) => void>(\n undefined\n );\n\n useEffect(() => {\n const isDirtyNow = cleanVersionNumber !== getFormData()?.fmFormDataVersion;\n setIsDirty(isDirtyNow);\n if (props.suppressPrompt) return;\n // Set up browser to check for exiting\n if (isDirtyNow && isDirty === false) {\n // Just got dirty...add listener\n beforeunloadListenerRef.current = beforeunloadListener;\n window.addEventListener(\"beforeunload\", beforeunloadListenerRef.current);\n } else if (!isDirtyNow && isDirty) {\n if (beforeunloadListenerRef.current) {\n window.removeEventListener(\n \"beforeunload\",\n beforeunloadListenerRef.current\n );\n beforeunloadListenerRef.current = undefined;\n }\n }\n });\n\n // Remove beforeunload listener when we unmount\n useEffect(() => {\n return () => {\n if (beforeunloadListenerRef.current) {\n window.removeEventListener(\n \"beforeunload\",\n beforeunloadListenerRef.current\n );\n }\n };\n }, []);\n\n const doSubmit = async () => {\n const invalid = validators.current.find((validator) => {\n const errorMessage = validator(fmFormRenderProps.formData);\n if (errorMessage) {\n notifyError(errorMessage);\n return true;\n }\n });\n if (invalid) {\n return Promise.resolve();\n }\n setIsSubmitting(true);\n const promise = props\n .onSubmit(fmFormRenderProps) // form may want to update form data when call returns\n .then((data) => {\n if (isMountedRef.current === false) return data;\n setCleanVersion(getFormData().fmFormDataVersion);\n return data;\n })\n .catch((error) => {\n notifyError(error);\n throw error;\n })\n .finally(() => {\n // The submit might close the form.\n if (isMountedRef.current) setIsSubmitting(false);\n });\n if (props.suppressSpinner !== true) {\n busyPromise(promise);\n }\n return promise;\n };\n\n fmFormRenderProps.submit = () => {\n return doSubmit();\n };\n\n if (fetchedFailed) {\n return (\n \n There is no information to display.\n \n );\n }\n\n if (getFormData() === undefined) {\n return (\n \n Working...\n \n );\n }\n\n return (\n <>\n {props.suppressPrompt !== true && (\n \n \"Are you sure you want leave this page? You will lose unsaved data.\"\n }\n />\n )}\n\n \n {\n e.preventDefault();\n doSubmit();\n }}\n style={{ height: \"100%\", width: \"100%\" }}\n >\n \n \n \n \n );\n};\n\nconst Child = (props: {\n fmFormRenderProps: FmFormRenderProps;\n children: (fmFormRenderProps: FmFormRenderProps) => React.ReactNode;\n}) => {\n return <>{props.children(props.fmFormRenderProps)};\n};\n","import Menu from \"@material-ui/core/Menu\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { useIsMounted } from \"../hooks/useIsMounted\";\n\ntype Coordinate = number | null;\ninterface Position {\n x: Coordinate;\n y: Coordinate;\n}\nconst initialState: Position = {\n x: null,\n y: null,\n};\n\nexport interface PmProps {\n close: () => void;\n}\n\nexport interface PopupMenuProps {\n menuElements: (pmProps: PmProps) => JSX.Element[];\n children?: (pmProps: PmProps) => React.ReactNode;\n}\nexport const PopupMenu = (props: PopupMenuProps) => {\n const [state, setState] = React.useState(initialState);\n const [clickHandler, setClickHandler] = useState(() => {});\n const handleClick = (event: React.MouseEvent) => {\n event.preventDefault();\n setState({\n x: event.clientX - 2,\n y: event.clientY - 4,\n });\n };\n const isMountedRef = useIsMounted();\n const handleClose = () => {\n // Parent may unmount -- this prevents warning messages about setting state on unmounted components.\n if (isMountedRef.current) {\n setState(initialState);\n }\n };\n const pmProps = { close: () => handleClose() };\n return (\n <>\n \n {props.children(pmProps)}\n \n \n {props.menuElements(pmProps)}\n \n \n );\n};\n","export class AppError extends Error {\n constructor(\n message: string,\n public code: string,\n public isExpected: boolean\n ) {\n super(message);\n this.name = \"AppError\";\n }\n}\n\nexport enum AppErrorCode {\n ErrAbstractNotCurrent,\n}\n","import { AppError } from \"../domain/AppError\";\nimport { ApiRequest, ApiResponse, Payload } from \"../domain/serverContract\";\n\ninterface HttpResponse extends Response {\n parsedBody?: T;\n}\n\nexport async function http(request: RequestInfo): Promise> {\n const response: HttpResponse = await fetch(request);\n try {\n // may error if there is no body\n // const text = await response.text();\n\n response.parsedBody = await response.json();\n } catch (ex) {}\n\n if (!response.ok) {\n throw new Error(response.statusText);\n }\n return response;\n}\n\nexport async function post(\n path: string,\n body: any,\n args: RequestInit = { method: \"post\", body: JSON.stringify(body) }\n): Promise> {\n return await http(new Request(path, args));\n}\nexport async function makeRequest(\n request: ApiRequest,\n path: string\n) {\n const serverResponse = await post(origin + path, request);\n const body = serverResponse.parsedBody;\n if (body.errorMessage) {\n throw new AppError(body.errorMessage, body.errorCode, body.isExpectedError);\n }\n const response = serverResponse.parsedBody as ApiResponse;\n return { ...response.payload, timestamp: response.timestamp } as TResponse;\n}\n","import { getAuthIdToken } from \"../app/author/components/RouterTop\";\nimport { ApiRequest, Payload } from \"../domain/serverContract\";\nimport { makeRequest } from \"./http\";\n\nexport async function makeRequestWithAuthentication(\n request: ApiRequest,\n path: string\n) {\n const authIdToken = await getAuthIdToken();\n const apiRequest = { authIdToken, ...request };\n return makeRequest(apiRequest, path);\n}\n","import { makeRequestWithAuthentication } from \"../../../../http/authenticated\";\nimport {\n ApiResponseHeader,\n ApiResponse,\n} from \"../../../../domain/serverContract\";\nimport { User } from \"../domain/User\";\n\nexport interface BooleanFilter {\n value: boolean;\n isAny: boolean;\n}\n\nexport interface StringFilter {\n value: string;\n isAny: boolean;\n}\n\nexport interface IntFilter {\n value: number;\n isAny: boolean;\n}\n\nexport const convertStringToFilter = (value: string): StringFilter => {\n return { value, isAny: value == null || value === \"\" };\n};\n\nexport const convertBooleanToFilter = (value: boolean): BooleanFilter => {\n return { value, isAny: value == null };\n};\n\nexport const convertIntToFilter = (value: number): IntFilter => {\n return { value, isAny: value == null };\n};\n\nexport interface Filter {\n uid: StringFilter;\n email: StringFilter;\n emailVerified: BooleanFilter;\n displayName: StringFilter;\n admin: IntFilter;\n disabled: BooleanFilter;\n}\n\nexport const clearFilter = (f: Filter) => {\n f.admin.isAny = true;\n f.displayName.isAny = true;\n f.email.isAny = true;\n f.emailVerified.isAny = true;\n f.uid.isAny = true;\n f.disabled.isAny = true;\n};\n\nexport const isClear = (f: Filter) => {\n if (f == null) return true;\n return (\n f.admin.isAny &&\n f.displayName.isAny &&\n f.email.isAny &&\n f.emailVerified.isAny &&\n f.uid.isAny &&\n f.disabled.isAny\n );\n};\n\nexport interface GetUsersRequest {\n filter: Filter;\n}\n\nexport interface GetUsersResponse extends ApiResponseHeader {\n incomplete: boolean;\n users: User[];\n}\n\nexport async function getUsers(request: GetUsersRequest) {\n return makeRequestWithAuthentication(\n request,\n \"/api/admin/get_users\"\n );\n}\n","import { makeRequestWithAuthentication } from \"../../../../http/authenticated\";\nimport { ApiResponseHeader } from \"../../../../domain/serverContract\";\n\nexport interface SetAdminLevelRequest {\n tuid: string;\n admin: number;\n}\n\nexport interface SetAdminLevelResponse extends ApiResponseHeader {}\n\nexport async function setAdminLevel(\n request: SetAdminLevelRequest\n): Promise {\n return makeRequestWithAuthentication(request, \"/api/admin/set_admin_level\");\n}\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport clsx from \"clsx\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n flexDirection: \"column\",\n },\n });\n});\ninterface ColumnContainerProps {\n center?: boolean;\n className?: string;\n}\n\nexport const ColumnContainer: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport Button from \"@material-ui/core/Button\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n primaryButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n },\n secondaryButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n backgroundColor: \"lightgray\",\n },\n strongGuidingButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n backgroundColor: theme.palette.secondary.main,\n },\n mildGuidingButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n },\n subtleButton: {\n margin: \"0.2rem 0.2rem 0.2rem 0.2rem\",\n },\n });\n});\ninterface ButtonProps {\n onClick?: () => void;\n disabled?: boolean;\n \"aria-label\"?: string;\n type?: \"submit\" | \"button\";\n autoFocus?: boolean;\n color?: \"inherit\" | \"primary\" | \"secondary\" | \"default\";\n}\n\nexport const PrimaryButton: React.FunctionComponent = (props) => {\n const classes = useStyles();\n const onClick = props.onClick ? props.onClick : () => {};\n return (\n // wrap in div to prevent button from expanding to full width in wide components\n
\n \n {props.children}\n \n
\n );\n};\n\nexport const SecondaryButton: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n\nexport const StrongGuidingButton: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n\nexport const MildGuidingButton: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n\nexport const SubtleButton: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return (\n props.onClick && props.onClick()}\n type={props.type ?? \"button\"}\n autoFocus={props.autoFocus}\n >\n {props.children}\n \n );\n};\n","import MuiDialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport * as React from \"react\";\nimport { useEffect } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { SubtleButton } from \"../buttons\";\nimport { getDialogMethods, makeDialog, Dialog } from \"./DialogManager\";\n\nexport interface ConfirmationDialogBaseProps {\n open: boolean;\n onClose: (isOk: boolean) => void;\n title: string;\n okayText?: string;\n}\n\nexport const ConfirmationDialogBase: React.FunctionComponent = (\n props\n) => {\n const { onClose, open, okayText, title } = props;\n\n const handleCancel = () => {\n onClose(false);\n };\n\n const handleOk = () => {\n onClose(true);\n };\n const history = useHistory();\n useEffect(() => {\n // Some apps may not use router.\n if (!history) return;\n // To start listening for location changes...\n return history.listen(() => {\n onClose(false);\n });\n }, []);\n\n return (\n \n {title}\n {props.children}\n \n \n Cancel\n \n {okayText ?? \"Ok\"}\n \n \n );\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n body: {\n margin: \"0.25rem 0 0.25rem 0\",\n fontSize: theme.typography.body1.fontSize,\n },\n });\n});\nexport interface SettingDescriptionProps {}\n\nconst SettingDescription: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return
{props.children}
;\n};\nexport default SettingDescription;\n","import * as React from \"react\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport clsx from \"clsx\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n flexDirection: \"row\",\n alignItems: \"center\",\n },\n });\n});\ninterface RowContainerProps {\n center?: boolean;\n width?: string;\n className?: string;\n}\n\nexport const RowContainer: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n","import { Checkbox, CheckboxProps, Slider, Typography } from \"@material-ui/core\";\nimport FormControlLabel from \"@material-ui/core/FormControlLabel\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Switch, { SwitchProps } from \"@material-ui/core/Switch\";\nimport TextField, { TextFieldProps } from \"@material-ui/core/TextField\";\nimport * as React from \"react\";\nimport { useContext, useEffect, useRef, useState } from \"react\";\nimport { notifyError } from \"../components/NotificationManager\";\nimport { RowContainer } from \"../components/RowContainer\";\nimport { FmFormContext, FmFormRenderProps } from \"./FmForm\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n text: {\n marginTop: \"8px\",\n marginBottom: \"8px\",\n },\n });\n});\n\nconst toLabelFromVariableName = (name: string) => {\n const nameArray = [...(name ?? [])];\n const labelLetters = nameArray.reduce((result, letter, index) => {\n const upcase = letter.toUpperCase();\n if (index === 0) {\n result.push(upcase);\n } else if (upcase !== letter) {\n result.push(letter);\n } else if (nameArray[index - 1] === nameArray[index - 1].toUpperCase()) {\n // Don't add a space between consecutive capitals\n result.push(letter);\n } else {\n // Add a space\n result.push(\" \");\n result.push(letter);\n }\n return result;\n }, [] as string[]);\n return labelLetters.join(\"\");\n};\n\nexport const FmTextField = (props: {\n name?: keyof TFormData & string;\n // valueProxyFuncs lets parent deal with state updates\n valueProxyFuncs?: {\n get: () => string;\n mutate: (value: string) => void;\n };\n error?: boolean;\n errorText?: string;\n textFieldProps?: TextFieldProps;\n initialFocus?: boolean;\n readOnly?: boolean;\n labelText?: string;\n placeholderText?: string;\n maxLength?: number;\n width?: string;\n forceToLowerCase?: boolean;\n isRequired?: boolean;\n className?: string;\n inputType?: \"text\" | \"number\" | \"password\";\n onChange?: (args: {\n oldFieldData: string;\n fieldData: string;\n draftFormData: TFormData;\n }) => void;\n onBlur?: (args: {\n fieldData: string;\n formData: TFormData;\n setErrorMessage: (message: string) => void;\n }) => void;\n}) => {\n const {\n name,\n textFieldProps,\n labelText,\n className,\n placeholderText,\n valueProxyFuncs,\n } = props;\n\n if (name == null && valueProxyFuncs == null) {\n console.error(\"Need either name or valueProxyFuncs\");\n }\n if (valueProxyFuncs && props.onChange) {\n console.error(\"Cannot use both onChange and valueProxyFuncs\");\n }\n const label = labelText ?? toLabelFromVariableName(name as string);\n const fmFormContext = useContext(FmFormContext) as FmFormRenderProps<\n TFormData\n >;\n const { formData, setFormData } = fmFormContext;\n const ref = useRef(null);\n useEffect(() => {\n if (!props.initialFocus) return;\n const inputElement: HTMLInputElement = ref.current;\n if (inputElement) inputElement.focus();\n }, []);\n\n const classes = useStyles();\n\n const fieldData = valueProxyFuncs ? valueProxyFuncs.get() : formData[name];\n\n useEffect(() => {\n if (props.isRequired) {\n fmFormContext.registerValidator((formData: TFormData) => {\n const value = valueProxyFuncs ? valueProxyFuncs.get() : formData[name];\n if (typeof value === \"string\") {\n return value.length > 0\n ? undefined\n : `Field \"${label}\" requires a value.`;\n }\n console.error(\"Should not get here.\");\n });\n }\n }, []);\n\n const typeProp = props.inputType ? { type: props.inputType } : {};\n const newTextFieldProps = { ...typeProp, ...textFieldProps };\n\n const [internalErrorMessage, setInternalErrorMessage] = useState(\"\");\n\n return (\n \n {\n let textInput = props.forceToLowerCase\n ? event.currentTarget.value.toLowerCase()\n : event.currentTarget.value;\n if (textInput.length > props.maxLength ?? Number.MAX_VALUE) return;\n if (valueProxyFuncs) {\n valueProxyFuncs.mutate(textInput);\n return;\n }\n setFormData((draftFormData) => {\n const oldFieldData = ((draftFormData as any)[\n name as keyof TFormData\n ] as any) as string;\n\n (draftFormData as any)[name] = textInput;\n\n // The onChange function should change draftFormData directly.\n props.onChange &&\n props.onChange({\n oldFieldData,\n fieldData: textInput,\n draftFormData: draftFormData as TFormData,\n });\n });\n // send old value and new value\n }}\n onBlur={(event) => {\n if (!props.onBlur) return;\n props.onBlur({\n fieldData: fieldData as string,\n formData,\n setErrorMessage: setInternalErrorMessage,\n });\n }}\n />\n \n );\n};\n\nconst positiveIntegers = /^\\d+$/;\n\nexport enum FmFieldErrorCode {\n \"OverMax\",\n \"UnderMin\",\n}\n\nexport const FmNumberField = (props: {\n name?: keyof TFormData & string;\n // Let parent deal with state updates\n valueProxyFuncs?: {\n get: () => number;\n mutate: (value: number) => void;\n };\n textFieldProps?: TextFieldProps;\n initialFocus?: boolean;\n labelText?: string;\n placeholderText?: string;\n maxLength?: number;\n width?: string;\n className?: string;\n inputType?: \"text\" | \"number\";\n minValue?: number;\n maxValue?: number;\n onChange?: (args: {\n oldValue: number;\n value: number;\n draftFormData: TFormData;\n }) => void;\n onFocus?: () => void;\n onBlur?: () => void;\n stringToValue?: (stringValue: string) => number;\n valueToString?: (value: number) => string;\n disabled?: boolean;\n customErrorMessages?: Partial>;\n}) => {\n const {\n name,\n textFieldProps,\n labelText,\n className,\n placeholderText,\n valueProxyFuncs,\n onChange,\n onBlur,\n onFocus,\n customErrorMessages,\n } = props;\n\n if (name == null && valueProxyFuncs == null) {\n console.error(\"Need either name or valueProxyFuncs\");\n }\n if (valueProxyFuncs && onChange) {\n console.error(\"Cannot use both onChange and valueProxyFuncs\");\n }\n\n // Handling only whole numbers...need to enhance later\n const stringToValue =\n props.stringToValue ??\n ((stringValue: string) => (stringValue == null ? 0 : Number(stringValue)));\n const valueToString =\n props.valueToString ??\n ((value: number) => (value == null ? \"\" : value.toString()));\n\n const minValue = props.minValue ?? 0;\n const maxValue = props.maxValue ?? Number.MAX_VALUE;\n const maxLength = props.maxLength ?? 10;\n const label = labelText ?? toLabelFromVariableName(name as string);\n const fmFormContext = useContext(FmFormContext) as FmFormRenderProps<\n TFormData\n >;\n const { formData, setFormData } = fmFormContext;\n const [hasFocus, setHasFocus] = useState(false);\n const formDataValue = valueProxyFuncs\n ? valueProxyFuncs.get()\n : ((formData[name] as unknown) as number);\n const [stringValue, setStringValue] = useState(valueToString(formDataValue));\n const ref = useRef(null);\n useEffect(() => {\n if (!props.initialFocus) return;\n const inputElement: HTMLInputElement = ref.current;\n if (inputElement) inputElement.focus();\n }, []);\n\n const typeProp = props.inputType\n ? { type: props.inputType }\n : { type: \"text\" };\n const newTextFieldProps = { ...typeProp, ...textFieldProps };\n const fieldValue = hasFocus ? stringValue : valueToString(formDataValue);\n const handleChange = (stringValue: string) => {\n const value = stringToValue(stringValue);\n if (value === formDataValue) return; // no change\n if (value < minValue) {\n notifyError(\n customErrorMessages?.[FmFieldErrorCode.UnderMin] ??\n `The value cannot be small than ${valueToString(minValue)}`\n );\n return;\n }\n if (value > maxValue) {\n notifyError(\n customErrorMessages?.[FmFieldErrorCode.OverMax] ??\n `The value cannot be greater than ${valueToString(maxValue)}`\n );\n return;\n }\n if (valueProxyFuncs) {\n valueProxyFuncs.mutate(value);\n return;\n }\n\n setFormData((draftFormData) => {\n const oldFieldData = (draftFormData as unknown)[name] as number;\n\n (draftFormData as unknown)[name] = value;\n\n // The onChange function should change draftFormData directly.\n props.onChange &&\n props.onChange({\n oldValue: oldFieldData,\n value: value,\n draftFormData: draftFormData as TFormData,\n });\n });\n };\n return (\n \n {\n setHasFocus(true);\n setStringValue(valueToString(formDataValue));\n onFocus && onFocus();\n },\n onBlur: () => {\n setHasFocus(false);\n handleChange(stringValue);\n onBlur && onBlur();\n },\n }}\n {...newTextFieldProps}\n onChange={(event) => {\n const textInput: string = event.target.value;\n\n // Only support non-negative ints for now\n if (textInput !== \"\" && !positiveIntegers.test(textInput)) return;\n if (textInput.length > maxLength) return;\n const value =\n textInput == null || textInput === \"\"\n ? 0\n : stringToValue(textInput);\n\n if (hasFocus) {\n setStringValue(textInput);\n return;\n }\n handleChange(textInput);\n }}\n />\n \n );\n};\n\nexport const FmSwitchField = (props: {\n name: keyof TFormData & string;\n switchFieldProps?: SwitchProps;\n labelText?: string;\n width?: string;\n className?: string;\n onChange?: (args: { fieldData: boolean; draftFormData: TFormData }) => void;\n}) => {\n const { name, labelText, className, switchFieldProps } = props;\n const label = labelText ?? toLabelFromVariableName(name as string);\n const fmFormContext = useContext(FmFormContext) as FmFormRenderProps<\n TFormData\n >;\n const { formData, setFormData } = fmFormContext;\n\n return (\n {\n const newFieldData = event.currentTarget.checked;\n setFormData((draftFormData) => {\n (draftFormData as unknown)[name] = newFieldData;\n\n // The onChange function should change draftFormData directly.\n props.onChange &&\n props.onChange({\n fieldData: newFieldData,\n draftFormData: draftFormData as TFormData,\n });\n });\n // send old value and new value\n }}\n />\n }\n label={label}\n />\n );\n};\n\nexport const FmCheckboxField = (props: {\n name: keyof TFormData & string;\n checkboxFieldProps?: CheckboxProps;\n labelText?: string;\n width?: string;\n className?: string;\n onChange?: (args: { fieldData: boolean; draftFormData: TFormData }) => void;\n}) => {\n const { name, labelText, className, checkboxFieldProps } = props;\n const label = labelText ?? toLabelFromVariableName(name as string);\n const fmFormContext = useContext(FmFormContext) as FmFormRenderProps<\n TFormData\n >;\n const { formData, setFormData } = fmFormContext;\n const value = (formData[name] as unknown) as boolean;\n return (\n {\n // const newFieldData = event.currentTarget.checked;\n const currentValue = (formData[name] as unknown) as boolean;\n const newValue =\n currentValue === true\n ? false\n : currentValue === false\n ? undefined\n : true;\n setFormData((draftFormData) => {\n (draftFormData as unknown)[name] = newValue;\n props.onChange &&\n props.onChange({\n fieldData: newValue,\n draftFormData: draftFormData as TFormData,\n });\n });\n }}\n />\n }\n label={label}\n />\n );\n};\n\nexport const FmDiscreteSliderField = (props: {\n name?: keyof TFormData & string;\n // Let parent deal with state updates\n valueProxyFuncs?: {\n get: () => TData;\n mutate: (value: TData) => void;\n };\n labelText?: string;\n width?: string;\n className?: string;\n // Sliders run from 0 through 100\n // marks used to map form data values to/from slider values\n marks: { value: TData; label: string }[];\n onChange?: (args: {\n oldValue: TData;\n value: TData;\n draftFormData: TFormData;\n }) => void;\n disabled?: boolean;\n}) => {\n const {\n name,\n labelText,\n className,\n valueProxyFuncs,\n onChange,\n disabled,\n } = props;\n\n if (name == null && valueProxyFuncs == null) {\n console.error(\"Need either name or valueProxyFuncs\");\n }\n if (valueProxyFuncs && onChange) {\n console.error(\"Cannot use both onChange and valueProxyFuncs\");\n }\n const scale = 100 / (props.marks.length - 1);\n const marks = props.marks.map((mark, index) => {\n return { value: index * scale, label: mark.label };\n });\n\n const mapIn = (formDataValue: TData) => {\n return (\n props.marks.findIndex((mark) => mark.value === formDataValue) * scale\n );\n };\n const mapOut = (scaleValue: number) => {\n return props.marks[Math.round(scaleValue / scale)].value;\n };\n const label = labelText ?? toLabelFromVariableName(name as string);\n const fmFormContext = useContext(FmFormContext) as FmFormRenderProps<\n TFormData\n >;\n const { formData, setFormData } = fmFormContext;\n const formDataValue = valueProxyFuncs\n ? valueProxyFuncs.get()\n : ((formData[name] as unknown) as TData);\n\n const handleChange = (value: TData) => {\n if (value === formDataValue) return; // no change\n if (valueProxyFuncs) {\n valueProxyFuncs.mutate(value);\n return;\n }\n\n setFormData((draftFormData) => {\n const oldFieldData = (draftFormData as unknown)[name] as TData;\n\n (draftFormData as unknown)[name] = value;\n\n // The onChange function should change draftFormData directly.\n props.onChange &&\n props.onChange({\n oldValue: oldFieldData,\n value: value,\n draftFormData: draftFormData as TFormData,\n });\n });\n };\n return (\n \n \n \n {label}\n \n {\n return marks[index].label;\n }}\n aria-labelledby=\"slider\"\n step={scale}\n valueLabelDisplay=\"off\"\n disabled={disabled}\n marks={marks}\n onChange={(_event, value: number) => {\n handleChange(mapOut(value));\n }}\n />\n \n \n );\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../components/ColumnContainer\";\nimport { ConfirmationDialogBase } from \"../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../components/SettingDescription\";\nimport { FmTextField } from \"../../../../formManager/FmField\";\nimport { FmForm } from \"../../../../formManager/FmForm\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n confirmationText: string;\n}\n\nexport interface ConfirmImpactfulActionDialogProps {\n confirmationText: string;\n dialogTitleAndOkayText: string;\n dialogContentRenderer: (confirmationText: string) => string | JSX.Element;\n}\n\nexport let ConfirmImpactfulActionDialogInternal: Dialog<\n void,\n ConfirmImpactfulActionDialogProps\n>;\n\nexport const openConfirmImpactfulActionDialog = (\n props: ConfirmImpactfulActionDialogProps\n) => {\n if (!ConfirmImpactfulActionDialogInternal) {\n ConfirmImpactfulActionDialogInternal = makeConfirmImpactfulActionDialogComponent();\n }\n return getDialogMethods().open(ConfirmImpactfulActionDialogInternal, props);\n};\n\nexport const makeConfirmImpactfulActionDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const props = dialogRenderProps.props;\n return (\n \n suppressPrompt\n name=\"ConfirmImpactfulActionDialog\"\n suppressSpinner\n fetch={{\n handler: () =>\n Promise.resolve({\n fmFormDataVersion: undefined,\n confirmationText: \"\",\n }),\n }}\n onSubmit={() => {\n return Promise.resolve();\n }}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: Date) => {\n dialogRenderProps.close(true);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false);\n }\n }}\n open={true}\n title={props.dialogTitleAndOkayText}\n okayText={props.dialogTitleAndOkayText}\n >\n \n \n {props.dialogContentRenderer(props.confirmationText)}\n \n \n \n \n )}\n \n );\n },\n });\n};\n","import * as React from \"react\";\nimport { SubtleButton } from \"../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../components/ColumnContainer\";\nimport { ConfirmationDialogBase } from \"../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../components/SettingDescription\";\nimport {\n FmCheckboxField,\n FmTextField,\n FmNumberField,\n} from \"../../../../formManager/FmField\";\nimport { FmForm } from \"../../../../formManager/FmForm\";\nimport {\n convertBooleanToFilter,\n convertStringToFilter,\n Filter,\n convertIntToFilter,\n} from \"../requests/getUsers\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n uid: string;\n email: string;\n emailVerified: boolean;\n displayName: string;\n admin: number;\n disabled: boolean;\n}\n\nexport interface FilterUsersDialogProps {\n filter: Filter;\n}\n\nexport let filterUsersDialogInternal: Dialog;\n\nexport const openFilterUsersDialog = (props: FilterUsersDialogProps) => {\n if (!filterUsersDialogInternal) {\n filterUsersDialogInternal = makeFilterUsersDialogComponent();\n }\n return getDialogMethods().open(filterUsersDialogInternal, props);\n};\n\nexport const makeFilterUsersDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const filter = dialogRenderProps.props.filter;\n return (\n \n suppressPrompt\n name=\"FilterUsersDialog\"\n suppressSpinner\n fetch={{\n handler: () =>\n Promise.resolve({\n fmFormDataVersion: undefined,\n uid: filter?.uid?.value ?? \"\",\n displayName: filter?.displayName?.value ?? \"\",\n email: filter?.email?.value ?? \"\",\n admin: filter?.admin?.isAny ? undefined : filter?.admin?.value,\n emailVerified: filter?.emailVerified?.isAny\n ? undefined\n : filter?.emailVerified?.value,\n disabled: filter?.disabled?.isAny\n ? undefined\n : filter?.disabled?.value,\n }),\n }}\n onSubmit={(fmProps) => {\n const f = fmProps.formData;\n const r: Filter = {\n displayName: convertStringToFilter(f.displayName),\n email: convertStringToFilter(f.email),\n admin: convertIntToFilter(f.admin),\n uid: convertStringToFilter(f.uid),\n emailVerified: convertBooleanToFilter(f.emailVerified),\n disabled: convertBooleanToFilter(f.disabled),\n };\n return Promise.resolve(r);\n }}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: Filter) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Filter\"}\n okayText={\"Set Filter\"}\n >\n \n {\n fmProps.setFormData((draft) => {\n draft.email = \"\";\n draft.displayName = \"\";\n draft.uid = \"\";\n draft.admin = undefined;\n draft.emailVerified = undefined;\n });\n }}\n >\n Clear Filter\n \n \n Enter filter criteria below\n \n name=\"uid\" width=\"25rem\" initialFocus />\n \n name=\"email\"\n width=\"25rem\"\n initialFocus\n />\n name=\"displayName\" width=\"25rem\" />\n name=\"emailVerified\" width=\"25rem\" />\n name=\"disabled\" width=\"25rem\" />\n name=\"admin\" width=\"25rem\" />\n \n \n )}\n \n );\n },\n });\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../components/ColumnContainer\";\nimport { ConfirmationDialogBase } from \"../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../components/SettingDescription\";\nimport { FmForm } from \"../../../../formManager/FmForm\";\nimport { DatePicker } from \"@material-ui/pickers\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n expiry: Date;\n}\n\nexport interface SetExpiryDialogProps {\n expiry: Date;\n}\n\nexport let setExpiryDialogInternal: Dialog;\n\nexport const openSetExpiryDialog = (props: SetExpiryDialogProps) => {\n if (!setExpiryDialogInternal) {\n setExpiryDialogInternal = makeSetExpiryDialogComponent();\n }\n return getDialogMethods().open(setExpiryDialogInternal, props);\n};\n\nexport const makeSetExpiryDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n return (\n \n suppressPrompt\n name=\"SetExpiryDialog\"\n suppressSpinner\n fetch={{\n handler: () =>\n Promise.resolve({\n fmFormDataVersion: undefined,\n expiry: dialogRenderProps.props.expiry,\n }),\n }}\n onSubmit={(fmProps) => {\n const f = fmProps.formData;\n return Promise.resolve(f.expiry);\n }}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: Date) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Set Expiration Date\"}\n okayText={\"Set Expiration Date\"}\n >\n \n \n Enter the subscription expiration date below. If the date is\n cleared, then the subscription will have no end date.\n \n {\n fmProps.setFormData((draft) => {\n draft.expiry = d;\n });\n }}\n />\n \n \n )}\n \n );\n },\n });\n};\n","import Grid from \"@material-ui/core/Grid\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport MenuItem from \"@material-ui/core/MenuItem\";\nimport FilterListIcon from \"@material-ui/icons/FilterList\";\nimport MoreVertIcon from \"@material-ui/icons/MoreVert\";\nimport RefreshIcon from \"@material-ui/icons/Refresh\";\nimport { format } from \"date-fns\";\nimport { Draft } from \"immer\";\nimport MaterialTable from \"material-table\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { busyPromise } from \"../../../../components/BusySpinner\";\nimport { notifyError } from \"../../../../components/NotificationManager\";\nimport { FmForm } from \"../../../../formManager/FmForm\";\nimport { PopupMenu } from \"../../../../components/PopupMenu\";\nimport { User } from \"../domain/User\";\nimport { deleteUser } from \"../requests/deleteUser\";\nimport { deleteUserGameData } from \"../requests/deleteUserGameData\";\nimport { disableUser } from \"../requests/disableUser\";\nimport { Filter, getUsers, isClear } from \"../requests/getUsers\";\nimport { setAdminLevel } from \"../requests/setAdminLevel\";\nimport { setExpiry } from \"../requests/setExpiry\";\nimport { openConfirmImpactfulActionDialog } from \"./ConfirmImpactfulActionDialog\";\nimport { openFilterUsersDialog } from \"./FilterUsersDialog\";\nimport { openSetExpiryDialog } from \"./SetExpiryDialog\";\n\nexport interface AdminUsersPageProps {}\n\nconst MoreActions = (props: {\n uid: string;\n admin: boolean;\n disabled: boolean;\n expiry: Date;\n email: string;\n}) => {\n return (\n \n {\n return [\n {\n setAdminLevel({\n tuid: props.uid,\n admin: 0,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n Remove Admin\n ,\n {\n setAdminLevel({\n tuid: props.uid,\n admin: 1,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n Make Admin\n ,\n {\n setAdminLevel({\n tuid: props.uid,\n admin: 2,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n Make Super Admin\n ,\n {\n disableUser({\n tuid: props.uid,\n disabled: !props.disabled,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n {props.disabled ? \"Enable user\" : \"Disable user\"}\n ,\n {\n const dr = await openSetExpiryDialog({\n expiry: props.expiry,\n });\n if (!dr.isOkay) return;\n setExpiry({\n tuid: props.uid,\n expiry: dr.result,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n {\"Set Expiration Date\"}\n ,\n {\n const dr = await openConfirmImpactfulActionDialog({\n dialogTitleAndOkayText: \"Delete User Game Data\",\n confirmationText: \"Delete User Game Data\",\n dialogContentRenderer: (confirmationText: string) => (\n
\n All user game data for {props.email} will be deleted. The\n user's profile and subscription data will be retained.\n This will fail unless the user's subscription is expired.\n You must type {confirmationText} in the field below\n to complete this action.\n
\n ),\n });\n if (!dr.isOkay) return;\n deleteUserGameData({\n tuid: props.uid,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n {\"Delete User Game Data\"}\n ,\n {\n const dr = await openConfirmImpactfulActionDialog({\n dialogTitleAndOkayText: \"Delete User\",\n confirmationText: \"Delete User\",\n dialogContentRenderer: (confirmationText: string) => (\n
\n The user {props.email} will be deleted. This will fail\n unless the user's subscription is expired, the user is\n diabled, and the user has no game data. You must type{\" \"}\n {confirmationText} in the field below to complete\n this action.\n
\n ),\n });\n if (!dr.isOkay) return;\n deleteUser({\n tuid: props.uid,\n }).catch((error) => notifyError(error));\n pmProps.close();\n }}\n >\n {\"Delete User\"}\n ,\n ];\n }}\n >\n {() => (\n \n \n \n )}\n \n
\n );\n};\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n users: User[];\n incomplete: boolean;\n filter: Filter;\n}\n\nconst fetchHandler = async (): Promise => {\n return {\n fmFormDataVersion: 0,\n users: [],\n incomplete: false,\n filter: undefined,\n };\n};\n\nexport const AdminUsersPage: React.FunctionComponent = () => {\n return (\n Promise.resolve()}\n >\n {(fmFormRenderProps) => {\n return (\n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n setFormData: (\n mutator: (formData: Draft) => FormData | void\n ) => FormData;\n formData: FormData;\n submit: () => Promise;\n isDirty: boolean;\n}) => {\n const { formData, setFormData } = props;\n const history = useHistory();\n\n const runSearch = async (filter: Filter) => {\n const r = await busyPromise(\n getUsers({ filter }).catch((error) => {\n notifyError(error.message);\n throw error;\n })\n );\n setFormData((draft) => {\n draft.users = r.users ?? [];\n });\n if (r.incomplete) {\n notifyError(\n \"The first 100 matching users were returned. There are more. Refine your search filter.\"\n );\n }\n props.submit(); // clears dirty flag\n };\n\n // Clone because\n // * immer makes data immutable\n // * table tries to add attributes (bummer)\n const tableData = formData.users.map((user) => {\n return {\n uid: user.uid,\n displayName: user.displayName,\n email: user.email,\n emailVerified: user.emailVerified,\n admin: user.admin,\n disabled: user.disabled,\n expiry: user.expiry,\n };\n });\n return (\n {\n return (\n
\n \n
\n );\n },\n },\n {\n title: \"UID\",\n field: \"uid\",\n cellStyle: {\n wordBreak: \"break-word\",\n },\n },\n {\n title: \"Email\",\n field: \"email\",\n cellStyle: {\n wordBreak: \"break-word\",\n },\n },\n {\n title: \"Email Verified\",\n field: \"emailVerified\",\n cellStyle: {\n wordBreak: \"break-word\",\n },\n },\n {\n title: \"Display Name\",\n field: \"displayName\",\n },\n {\n title: \"Admin\",\n field: \"admin\",\n },\n {\n title: \"Disabled\",\n field: \"disabled\",\n },\n {\n title: \"Expiry\",\n field: \"expiry\",\n render: (rowData) =>\n rowData.expiry\n ? format(new Date(rowData.expiry), \"P\")\n : rowData.expiry,\n },\n ]}\n data={tableData}\n options={{\n search: true,\n sorting: true,\n }}\n actions={[\n {\n icon: () => (\n \n ),\n tooltip: isClear(formData.filter) ? \"Set filter\" : \"Change filter\",\n isFreeAction: true,\n onClick: async () => {\n const dr = await openFilterUsersDialog({\n filter: formData.filter,\n });\n if (!dr.isOkay) return;\n setFormData((draftFormData) => {\n // Save the filter we just used\n draftFormData.filter = dr.result;\n });\n },\n },\n {\n icon: () => (\n \n ),\n tooltip: props.isDirty ? \"Refresh - filter changed\" : \"Refresh\",\n isFreeAction: true,\n onClick: () => {\n runSearch(formData.filter);\n },\n },\n ]}\n />\n );\n};\n","import { makeRequestWithAuthentication } from \"../../../../http/authenticated\";\nimport { ApiResponseHeader } from \"../../../../domain/serverContract\";\n\nexport interface DisableUserUserRequest {\n tuid: string;\n disabled: boolean;\n}\n\nexport interface DisableUserUserResponse extends ApiResponseHeader {}\n\nexport async function disableUser(\n request: DisableUserUserRequest\n): Promise {\n return makeRequestWithAuthentication(request, \"/api/admin/disable_user\");\n}\n","import { makeRequestWithAuthentication } from \"../../../../http/authenticated\";\nimport { ApiResponseHeader } from \"../../../../domain/serverContract\";\n\nexport interface SetExpiryRequest {\n tuid: string;\n expiry: Date; // undefined value clears expiry\n}\n\nexport interface SetExpiryResponse extends ApiResponseHeader {}\n\nexport async function setExpiry(\n request: SetExpiryRequest\n): Promise {\n return makeRequestWithAuthentication(request, \"/api/admin/set_expiry\");\n}\n","import { ApiResponseHeader } from \"../../../../domain/serverContract\";\nimport { makeRequestWithAuthentication } from \"../../../../http/authenticated\";\n\nexport interface DeleteUserGameDataRequest {\n tuid: string;\n}\n\nexport interface DeleteUserGameDataResponse extends ApiResponseHeader {}\n\nexport async function deleteUserGameData(\n request: DeleteUserGameDataRequest\n): Promise {\n return makeRequestWithAuthentication(\n request,\n \"/api/admin/delete_user_game_data\"\n );\n}\n","import { ApiResponseHeader } from \"../../../../domain/serverContract\";\nimport { makeRequestWithAuthentication } from \"../../../../http/authenticated\";\n\nexport interface DeleteUserRequest {\n tuid: string;\n}\n\nexport interface DeleteUserResponse extends ApiResponseHeader {}\n\nexport async function deleteUser(\n request: DeleteUserRequest\n): Promise {\n return makeRequestWithAuthentication(request, \"/api/admin/delete_user\");\n}\n","import Button from \"@material-ui/core/Button\";\nimport List from \"@material-ui/core/List\";\nimport ListItem from \"@material-ui/core/ListItem\";\nimport ListItemIcon from \"@material-ui/core/ListItemIcon\";\nimport ListItemText from \"@material-ui/core/ListItemText\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Toolbar from \"@material-ui/core/Toolbar\";\nimport Typography from \"@material-ui/core/Typography\";\nimport AddIcon from \"@material-ui/icons/AddBoxRounded\";\nimport SpellIcon from \"@material-ui/icons/FontDownload\";\nimport SettingsIcon from \"@material-ui/icons/Settings\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { Route, Switch, useHistory, useRouteMatch } from \"react-router-dom\";\nimport { notifyError } from \"../../../../components/NotificationManager\";\nimport { TopicFrame } from \"../../components/TopicFrame\";\nimport { AdminUsersPage } from \"./AdminUsersPage\";\n\nconst drawerWidth = 240;\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n appBar: {\n zIndex: theme.zIndex.drawer + 1,\n },\n drawer: {\n width: drawerWidth,\n flexShrink: 0,\n },\n drawerPaper: {\n width: drawerWidth,\n // position: \"static\",\n },\n drawerContainer: {\n overflow: \"auto\",\n },\n content: {\n flexGrow: 1,\n padding: theme.spacing(3),\n },\n nested: {\n paddingLeft: theme.spacing(4),\n },\n // Loads information about the app bar, including app bar height\n toolbar: theme.mixins.toolbar,\n });\n});\n\nenum Page {\n Users,\n Settings,\n}\n\nexport interface AdminTopicProps {\n admin: number;\n}\n\nexport const AdminTopic: React.FunctionComponent = (props) => {\n const classes = useStyles();\n const [settingsToolbar, setSettingsToolbar] = useState(null);\n\n const history = useHistory();\n let { path } = useRouteMatch();\n\n // Check to see if we're admin\n useEffect(() => {\n if (props.admin < 1) {\n notifyError(\"Not an admin.\");\n history.push(\"/home\");\n }\n }, []);\n\n const leftNav = (\n \n history.push(`${path}/users`)}>\n \n \n history.push(`${path}/settings`)}>\n \n \n \n \n \n \n );\n\n const usersToolbar = (\n \n \n Admin: Users\n \n \n \n );\n\n const [page, setPage] = useState(Page.Users);\n\n useEffect(() => {\n switch (history.location.pathname) {\n case `${path}/users`:\n case `${path}`:\n setPage(Page.Users);\n break;\n case `${path}/settings`:\n setPage(Page.Settings);\n break;\n default:\n setPage(Page.Users);\n break;\n }\n }, [history.location.pathname]);\n return (\n <>\n {\n history.push(`${path}/users`);\n }}\n >\n \n \n }\n appIconMenuText=\"Admin\"\n leftNav={leftNav}\n toolbar={\n page === Page.Users ? (\n usersToolbar\n ) : page === Page.Settings ? (\n {settingsToolbar}\n ) : (\n {usersToolbar}\n )\n }\n >\n \n {\n return (\n <>\n \n \n );\n }}\n />\n {\n return ;\n }}\n />\n {\n return null;\n // return ;\n }}\n />\n \n \n \n );\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport Divider from \"@material-ui/core/Divider\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n body: {\n margin: \"0.25rem 0 0.25rem 0\",\n fontSize: theme.typography.body1.fontSize,\n },\n });\n});\ninterface PageIntroProps {}\n\nconst PageIntro: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return (\n
\n {props.children}\n \n
\n );\n};\nexport default PageIntro;\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n marginLeft: \"1rem\",\n marginRight: \"1rem\",\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n },\n });\n});\ninterface SettingsContainerProps {\n horizontalAlignment?: \"center\" | \"flex-start\";\n}\n\nconst SettingsContainer: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n\nexport default SettingsContainer;\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n margin: \"1rem 0 1rem 0\",\n },\n });\n});\nexport interface TitleProps {}\n\nexport const Title: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n\nexport default Title;\n","import { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { useContext } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport {\n notifyError,\n notifySuccess,\n} from \"../../../components/NotificationManager\";\nimport PageIntro from \"../../../components/PageIntro\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { Title } from \"../../../components/Title\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { UserContext } from \"./RouterTop\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n newEmail: string;\n}\n\nexport interface ChangeEmailProps {}\n\nexport const ChangeEmail = () => {\n const history = useHistory();\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const auth = firebaseauth();\n const user = auth.currentUser;\n user\n .updateEmail(formData.newEmail)\n .then(function () {\n notifySuccess(\n \"Your email address has been changed. You should receive notification at your previous email address. \" +\n \" For security reasons, you have been logged off so that you might test your new email address by immediately logging in.\",\n () => history.push(\"/logoff\")\n );\n })\n .catch(function (error) {\n notifyError(error.message);\n });\n };\n const authUserInfo = useContext(UserContext);\n const initialFormData: FormData = {\n fmFormDataVersion: 0,\n newEmail: authUserInfo.email ?? \"\",\n };\n return (\n Promise.resolve(initialFormData) }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => (\n \n \n Change Email for {authUserInfo.displayName} ({authUserInfo.email})\n \n \n Once your email is changed, you will receive an email at your old\n email address. That email will contain a link to allow you to set\n your email back to your old address. You will also be logged off. In\n case you changed your email to the wrong address, you should\n immediately sign in again.\n \n name=\"newEmail\" initialFocus width=\"20rem\" />\n fmProps.submit()}\n disabled={\n fmProps.isSubmitting ||\n fmProps.isDirty !== true ||\n fmProps.formData.newEmail === authUserInfo.email\n }\n >\n Change email\n \n \n )}\n \n );\n};\n","import { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { useContext } from \"react\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport {\n notifyError,\n notifySuccess,\n} from \"../../../components/NotificationManager\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport Title from \"../../../components/Title\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { UserContext } from \"./RouterTop\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n password: string;\n}\n\nexport interface ChangePasswordProps {}\n\nexport const ChangePassword = () => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const auth = firebaseauth();\n const user = auth.currentUser;\n user\n .updatePassword(formData.password)\n .then(function () {\n notifySuccess(\"Your password has been changed.\");\n })\n .catch(function (error) {\n notifyError(error.message);\n });\n };\n const authUserInfo = useContext(UserContext);\n const initialFormData: FormData = {\n fmFormDataVersion: 0,\n password: \"\",\n };\n return (\n Promise.resolve(initialFormData) }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => (\n \n \n Change Password for {authUserInfo.displayName} ({authUserInfo.email}\n )\n \n \n name=\"password\"\n initialFocus\n width=\"20rem\"\n textFieldProps={{\n type: \"Password\",\n }}\n />\n fmProps.submit()}\n disabled={fmProps.isSubmitting || fmProps.isDirty !== true}\n >\n Change password\n \n \n )}\n \n );\n};\n","import { Divider } from \"@material-ui/core\";\nimport Dialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { SubtleButton } from \"../buttons\";\n\nexport interface InfoDialogProps {\n title: string;\n}\n\nexport const InfoDialog: React.FunctionComponent = (props) => {\n const [open, setOpen] = useState(true);\n return (\n setOpen(false)}\n open={open}\n title={props.title}\n >\n {props.children}\n \n );\n};\n\nexport interface InfoDialogBaseProps {\n open: boolean;\n onClose: (isOkay: boolean, result: unknown) => void;\n title: string;\n}\n\nexport const InfoDialogBase: React.FunctionComponent = (\n props\n) => {\n const { onClose, open, title } = props;\n\n const handleClose = () => {\n onClose(true, undefined);\n };\n\n return (\n \n {title}\n \n {props.children}\n \n handleClose()}>{\"Ok\"}\n \n \n );\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n flexDirection: \"column\",\n margin: \"0.5rem 1rem 0rem 1rem\",\n },\n });\n});\ninterface PageContainerProps {\n center?: boolean;\n}\n\nexport const PageContainer: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n margin: \"1rem 0 1rem 0\",\n },\n });\n});\ninterface SettingHeaderProps {}\n\nconst SettingHeader: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n\nexport default SettingHeader;\n","import { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { completeRegistration } from \"../requests/completeRegistration\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../components/dialogTools/DialogManager\";\nimport { InfoDialogBase } from \"../../../components/dialogTools/InfoDialog\";\nimport { notifyError } from \"../../../components/NotificationManager\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport PageIntro from \"../../../components/PageIntro\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { Title } from \"../../../components/Title\";\nimport SettingHeader from \"../../../components/SettingHeader\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n email: string;\n password: string;\n}\n\nexport interface CompleteRegistrationProps {}\n\nexport const CompleteRegistration = () => {\n const history = useHistory();\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const auth = firebaseauth();\n if (!auth.isSignInWithEmailLink(window.location.href)) {\n throw new Error(\n \"There was a problem with verifying your email address. You may have incorrectly copied the URL from the verification email.\"\n );\n }\n // signInWithEmailLink also verifies the email address\n auth\n .signInWithEmailLink(formData.email, window.location.href)\n .then(() => {\n window.localStorage.removeItem(\"emailForSignIn\");\n })\n .then(() => {\n // We're logged in.\n // Now we verify the email address by sending the registration token.\n const tokens = history.location.pathname.split(\"/\");\n const registrationToken = tokens[tokens.length - 1];\n return completeRegistration({\n registrationToken,\n password: formData.password,\n });\n })\n .then(() => {\n // sign in again, otherwise Firebase auth will throw an error in the normal\n // auth code in RouterTop. That's because the auth method changed from\n // an email link sign in to email/password.\n auth\n .signInWithEmailAndPassword(formData.email, formData.password)\n .then((_userCredential) => {\n openDialog({}).then(() => history.push(\"/home\"));\n });\n })\n .catch(function (error) {\n notifyError(error);\n });\n };\n return (\n {\n const email = window.localStorage.getItem(\"emailForSignIn\");\n return Promise.resolve({\n fmFormDataVersion: 0,\n email: email ?? \"\",\n password: \"\",\n });\n },\n }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => (\n \n Complete Registration\n \n Make sure your email address is correct, enter a password (which\n will be your password), then press Complete Registration. You will\n be able to create games immediately. If you forget your password,\n you can create a new one by pressing \"SEND PASSWORD RESET EMAIL\" on\n the login page.\n \n \n name=\"email\"\n initialFocus\n width=\"20rem\"\n isRequired\n />\n \n name=\"password\"\n inputType=\"password\"\n isRequired\n maxLength={100}\n width=\"25rem\"\n textFieldProps={{\n InputProps: {\n spellCheck: false,\n },\n }}\n />\n \n Complete Registration\n \n \n )}\n \n );\n};\n\ninterface Props {}\nexport let dialogInternal: Dialog;\n\nexport const openDialog = (props: Props) => {\n if (!dialogInternal) {\n dialogInternal = makeComponent();\n }\n return getDialogMethods().open(dialogInternal, props);\n};\n\nconst makeComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n return (\n {\n dialogRenderProps.close(false, undefined);\n }}\n open={true}\n title={\"Wahoo!\"}\n >\n \n Welcome to the Cortex\n \n We're glad you registered. If you have questions or comments,\n please send them to support@cortexplay.com. You're now ready to\n author your first game. Enjoy!\n \n \n \n );\n },\n });\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeRequestWithAuthentication } from \"../../../http/authenticated\";\n\nexport interface CompleteRegistrationRequest {\n registrationToken: string;\n password: string;\n}\n\nexport interface CompleteRegistrationResponse extends ApiResponseHeader {}\n\nexport async function completeRegistration(\n request: CompleteRegistrationRequest\n): Promise {\n return makeRequestWithAuthentication(request, \"/api/complete_registration\");\n}\n","import * as React from \"react\";\nimport { makeStyles, createStyles, Theme } from \"@material-ui/core/styles\";\nimport Paper from \"@material-ui/core/Paper\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n paper: {\n margin: \"0.5rem\",\n padding: \"0.5rem\",\n fontSize: theme.typography.body1.fontSize,\n },\n });\n});\nexport interface InfoProps {}\n\nexport const Info: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return {props.children};\n};\n","import Button from \"@material-ui/core/Button\";\nimport Dialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport InfoIcon from \"@material-ui/icons/Info\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { SubtleButton } from \"./buttons\";\nimport { Info } from \"./Info\";\n\nexport const TellMeMore: React.FunctionComponent<{\n icon?: boolean;\n message?: string | JSX.Element;\n buttonText?: string;\n color?: \"primary\" | \"secondary\" | \"default\" | \"inherit\";\n}> = (props) => {\n const [open, setOpen] = useState(false);\n return (\n <>\n {\n setOpen(true);\n }}\n >\n {props.icon ? (\n \n ) : props.buttonText ? (\n props.buttonText\n ) : (\n \"tell me more\"\n )}\n \n setOpen(false)}\n aria-labelledby=\"tell-me-more\"\n open={open}\n >\n {props.message ? props.message : props.children}\n \n setOpen(false)}>Ok\n \n \n \n );\n};\n","import { makeRequestWithAuthentication } from \"../../../http/authenticated\";\nimport {\n GameAbstract,\n GameAbstractsRecord,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { GameType } from \"../../../domain/types\";\n\nexport interface GetGameAbstractsRecordRequest {}\n\nexport interface GetGameAbstractsRecordResponse extends ValidatedApiResponse {\n gameAbstractsRecord: GameAbstractsRecord;\n}\n\nasync function getGameAbstractsRecord(): Promise<\n GetGameAbstractsRecordResponse\n> {\n return makeRequestWithAuthentication({}, \"/api/get_game_abstracts_record\");\n}\n\n// versionChangeHandler returns the new version\ninterface versionChangeHandler {\n (version: string): void;\n}\n\nlet registrationId = -1;\nconst registrations: Record = Object.create(null);\nconst unregister = (regId: number) => delete registrations[regId];\nexport const registerTimestampChangeHandler = (\n handler: versionChangeHandler\n) => {\n registrations[++registrationId] = handler;\n return () => unregister(registrationId);\n};\n\nlet gameAbstractsRecordCache: GameAbstractsRecord;\nexport const bustGameAbstractsRecordCache = () => {\n promiseCache = undefined;\n};\n\nexport const getAbstractsVersion = () => gameAbstractsRecordCache?.version;\n\nexport const updateAbstractsVersion = (version: string) => {\n gameAbstractsRecordCache.version = version;\n};\n\nexport const notifyHandlers = () => {\n Object.values(registrations).forEach((handler) =>\n handler(gameAbstractsRecordCache.version)\n );\n};\n\nlet promiseCache: Promise;\n\nexport const gameAbstractsRecord = async () => {\n if (promiseCache) return promiseCache;\n\n promiseCache = getGameAbstractsRecord()\n .then((response) => {\n if (response.gameAbstractsRecord.gameAbstracts == null) {\n response.gameAbstractsRecord.gameAbstracts = {};\n }\n // Denormalize game ID from map key\n response.gameAbstractsRecord.gameAbstracts &&\n Object.keys(response.gameAbstractsRecord.gameAbstracts).map((key) => {\n response.gameAbstractsRecord.gameAbstracts[key].id = key;\n });\n gameAbstractsRecordCache = response.gameAbstractsRecord;\n gameAbstractsRecordCache.version = response.version;\n // The cache is capture via closure, so when we update the cache we update the promise result.\n return gameAbstractsRecordCache;\n })\n .catch((error) => {\n promiseCache = undefined;\n throw error;\n });\n return promiseCache;\n};\n\n//\n// Shadow database operations\n//\n\nexport const insertAbstract = (args: {\n gameType: GameType;\n gameId: string;\n name: string;\n title: string;\n subtitle: string;\n description: string;\n timestamp: Date;\n}) => {\n const abstract: GameAbstract = {\n trashed: false,\n deleted: false,\n gameType: args.gameType,\n id: args.gameId,\n name: args.name,\n title: args.title,\n subtitle: args.subtitle,\n description: args.description,\n created: args.timestamp,\n modified: args.timestamp,\n published: undefined,\n plays: undefined,\n template: false,\n };\n gameAbstractsRecordCache.gameAbstracts[args.gameId] = abstract;\n // promiseCache = Promise.resolve(gameAbstractsRecordCache);\n notifyHandlers();\n};\n\nexport const updateAbstract = (\n gameId: string,\n mutator: (gameAbstract: GameAbstract) => void\n) => {\n const abstract = gameAbstractsRecordCache.gameAbstracts[gameId];\n if (abstract == null) throw new Error(\"No abstract for gameId \" + gameId);\n const { created } = abstract;\n mutator(abstract);\n if (abstract.modified == null) throw new Error(\"modified cannot be null\");\n if (abstract.created !== created) {\n throw new Error(\"created cannot be changed\");\n }\n //promiseCache = Promise.resolve(gameAbstractsRecordCache);\n notifyHandlers();\n};\n\nexport const trashAbstract = (gameId: string, timestamp: Date) => {\n const abstract = gameAbstractsRecordCache.gameAbstracts[gameId];\n if (abstract == null) throw new Error(\"No abstract for gameId \" + gameId);\n if (timestamp == null) throw new Error(\"timestamp cannot be null\");\n if (timestamp < abstract.modified) {\n throw new Error(\"timestamp must be later than previous modified time\");\n }\n abstract.trashed = true;\n abstract.modified = timestamp;\n //promiseCache = Promise.resolve(gameAbstractsRecordCache);\n notifyHandlers();\n};\n\nexport const untrashAbstract = (\n gameId: string,\n timestamp: Date,\n name: string\n) => {\n const abstract = gameAbstractsRecordCache.gameAbstracts[gameId];\n if (abstract == null) throw new Error(\"No abstract for gameId \" + gameId);\n if (timestamp == null) throw new Error(\"timestamp cannot be null\");\n if (timestamp < abstract.modified) {\n throw new Error(\"timestamp must be later than previous modified time\");\n }\n abstract.trashed = false;\n abstract.modified = timestamp;\n abstract.name = name;\n //promiseCache = Promise.resolve(gameAbstractsRecordCache);\n notifyHandlers();\n};\n\nexport const deleteAbstract = (gameId: string, timestamp: Date) => {\n const abstract = gameAbstractsRecordCache.gameAbstracts[gameId];\n if (abstract == null) throw new Error(\"No abstract for gameId \" + gameId);\n if (timestamp == null) throw new Error(\"timestamp cannot be null\");\n if (timestamp < abstract.modified) {\n throw new Error(\"timestamp must be later than previous modified time\");\n }\n abstract.deleted = true;\n //promiseCache = Promise.resolve(gameAbstractsRecordCache);\n notifyHandlers();\n};\n\nexport const deleteTrashedAbstracts = () => {\n const abstracts = gameAbstractsRecordCache.gameAbstracts;\n Object.values(abstracts)\n .filter((abstract) => abstract.trashed)\n .forEach((abstract) => (abstract.deleted = true));\n //promiseCache = Promise.resolve(gameAbstractsRecordCache);\n notifyHandlers();\n};\n\n// finds untrashed games only\nconst findGameAbstractByName = (name: string) =>\n Object.values(gameAbstractsRecordCache.gameAbstracts).find(\n (abstract) => abstract.name === name && abstract.trashed !== true\n );\n\nexport const getUniqueName = (baseName: string) => {\n let name = baseName;\n let index = 0;\n while (true) {\n if (!findGameAbstractByName(name)) return name;\n index++;\n name = baseName + \"-undeleted-\" + index;\n }\n};\n","import { AppError, AppErrorCode } from \"../../../domain/AppError\";\nimport {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { makeRequestWithAuthentication } from \"../../../http/authenticated\";\nimport {\n bustGameAbstractsRecordCache,\n gameAbstractsRecord,\n updateAbstractsVersion,\n} from \"./manageGameAbstracts\";\n\n// makeCacheValidatedRequest sends the abstract timestamp to the server as part of the request.\n// It handles ErrAbstractNotCurrent with an appropriate error message,\n// and it busts the cache.\nexport const makeCacheValidatedRequest = async <\n TResponse extends ValidatedApiResponse\n>(\n request: ApiRequest,\n path: string\n) => {\n const record = await gameAbstractsRecord();\n const vrequest = { ...request, version: record.version };\n return makeRequestWithAuthentication(vrequest, path)\n .then((response) => {\n updateAbstractsVersion(response.version);\n return response;\n })\n .catch((error) => {\n if (\n error instanceof AppError &&\n error.code === AppErrorCode[AppErrorCode.ErrAbstractNotCurrent]\n ) {\n // Need to re-fetch the abstracts\n bustGameAbstractsRecordCache();\n throw new AppError(\n [\n \"Error: you may be making changes from different devices or browser tabs at the same time.\",\n \"Refresh the page to get current data, and then retry your changes.\",\n ].join(\" \"),\n error.code,\n error.isExpected\n );\n }\n throw error;\n });\n};\n","import {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { insertAbstract } from \"./manageGameAbstracts\";\nimport { GameType } from \"../../../domain/types\";\n\nexport interface CreateGameRequest extends ApiRequest {\n name: string;\n templateGameRef?: string;\n gameType: GameType;\n}\n\nexport interface CreateGameResponse extends ValidatedApiResponse {\n id: string;\n title: string;\n subtitle: string;\n description: string;\n}\n\nexport async function createGame(\n request: CreateGameRequest\n): Promise {\n return makeCacheValidatedRequest(\n request,\n \"/api/create_game\"\n ).then((response) => {\n // Create abstract\n insertAbstract({\n gameType: request.gameType,\n gameId: response.id,\n timestamp: response.timestamp,\n name: request.name,\n title: response.title,\n subtitle: response.subtitle,\n description: response.description,\n });\n return response as CreateGameResponse;\n });\n}\n","import {\n FormControl,\n InputLabel,\n MenuItem,\n Select,\n makeStyles,\n} from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport { ConfirmationDialogBase } from \"../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../components/NotificationManager\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport { TellMeMore } from \"../../../components/TellMeMore\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { createGame, CreateGameResponse } from \"../requests/createGame\";\nimport { GameType } from \"../../../domain/types\";\nconst useStyles = makeStyles((theme) => ({\n formControl: {\n minWidth: \"15rem\",\n margin: \"1rem\",\n },\n}));\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n name: string;\n gameType: GameType;\n}\nexport interface AddGameDialogProps {\n title: string;\n // The gameRef can be a game ID or a progress ID.\n templateGameRef?: string;\n gameType?: GameType;\n gameName?: string;\n}\n\nlet addGameDialogInternal: Dialog;\n\nexport const openAddGameDialog = (props: AddGameDialogProps) => {\n if (!addGameDialogInternal) {\n addGameDialogInternal = makeAddGameDialog();\n }\n return getDialogMethods().open(addGameDialogInternal, props);\n};\n\nconst makeAddGameDialog = () =>\n makeDialog({\n name: \"AddGameDialog\",\n componentRenderer: (dialogRenderProps) => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n return createGame({\n name: formData.name,\n templateGameRef: dialogRenderProps.props?.templateGameRef,\n gameType: formData.gameType,\n });\n };\n\n const history = useHistory();\n const classes = useStyles();\n return (\n \n Promise.resolve({\n name: dialogRenderProps.props.gameName ?? \"\",\n fmFormDataVersion: undefined,\n gameType: dialogRenderProps.props.gameType ?? \"t\",\n }),\n }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => {\n return (\n {\n if (isOkay) {\n // Create the game\n return fmProps\n .submit()\n .then((response: CreateGameResponse) => {\n dialogRenderProps.close(true, undefined);\n history.push(`/games/edit/${response.id}`);\n return response;\n })\n .catch((error: Error) => {\n notifyError(error.message);\n });\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={dialogRenderProps.props.title}\n okayText=\"Create Game\"\n >\n \n {dialogRenderProps.props.gameType == null && (\n \n Game Type\n \n ) => {\n fmProps.setFormData((draft) => {\n draft.gameType = event.target.value as GameType;\n });\n }}\n >\n Spell\n Compute\n Twist\n \n \n )}\n \n Enter the name of your new game (no spaces), then press\n Create Game. Once you add the game, you can customize it.\n The name must be unique.\n \n The name must consist entirely of letters, digits,\n underscores, and dashes. This allows the name to be easily\n read in URLs, so that you can identify the game to which a\n URL refers.\n \n \n \n name=\"name\"\n maxLength={20}\n initialFocus\n textFieldProps={{\n InputProps: {\n spellCheck: false,\n },\n }}\n />\n \n \n );\n }}\n \n );\n },\n });\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeRequestWithAuthentication } from \"../../../http/authenticated\";\nimport { GameRecord } from \"../../../domain/types\";\n\nexport interface GetGameRequest {\n id: string;\n}\n\nexport interface GetGameResponse extends ApiResponseHeader {\n id: string;\n name: string;\n gameRecord: GameRecord;\n}\n\nexport async function getGame(\n request: GetGameRequest\n): Promise {\n return makeRequestWithAuthentication(request, \"/api/get_game\");\n}\n","import Box from \"@material-ui/core/Box\";\nimport Grid from \"@material-ui/core/Grid\";\nimport * as React from \"react\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmForm } from \"../../../../../formManager/FmForm\";\nimport { openAddGameDialog } from \"../../../components/AddGameDialog\";\nimport { getGame } from \"../../../requests/getGame\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n url: string;\n}\n\nexport interface ImportGameDialogProps {}\n\nexport let getWordsDialogInternal: Dialog;\n\nexport const openImportGameDialog = (props: ImportGameDialogProps) => {\n if (!getWordsDialogInternal) {\n getWordsDialogInternal = makeImportGameDialogComponent();\n }\n return getDialogMethods().open(getWordsDialogInternal, props);\n};\n\nexport const makeImportGameDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n return (\n \n Promise.resolve({ url: \"\", fmFormDataVersion: undefined }),\n }}\n onSubmit={async (fmProps) => {\n // Pull out the gameRef from the URL.\n // First, strip any query params.\n // Then take token after last /\n const url = fmProps.formData.url;\n if (url.length === 0) return;\n const t1s = url.split(\"?\");\n const t2s = t1s[0].split(\"/\");\n const gameRef = t2s[t2s.length - 1];\n const r = await getGame({ id: gameRef });\n openAddGameDialog({\n templateGameRef: gameRef, // use this game as the template\n title: \"Import Game\",\n gameType: r.gameRecord.gameType,\n });\n // Just want to close this dialog\n dialogRenderProps.close(false, undefined);\n return Promise.resolve();\n }}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: string[]) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Import Game\"}\n okayText={\"Next\"}\n >\n \n \n Enter the URL for the game you wish to import. On the next\n page you will be able to specify the name of your game.\n \n \n \n name=\"url\" width=\"100%\" initialFocus />\n \n \n \n )}\n \n );\n },\n });\n};\n","import Button from \"@material-ui/core/Button\";\nimport AddIcon from \"@material-ui/icons/AddBoxRounded\";\nimport * as React from \"react\";\n\ninterface CreateGameButtonProps {\n onClick?: () => void;\n}\n\nexport const CreateGameButton: React.FunctionComponent = (\n props\n) => {\n return (\n \n );\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n container: {\n display: \"flex\",\n flexWrap: \"wrap\",\n flexDirection: \"column\",\n margin: \"6rem 1rem 0rem 1rem\",\n justifyContent: \"center\",\n alignItems: \"center\",\n },\n });\n});\ninterface NotFoundProps {}\n\nexport const NotFound: React.FunctionComponent = (props) => {\n const classes = useStyles();\n return (\n
\n {props.children ?? \"Nothing to display. Try navigating elsewhere.\"}\n
\n );\n};\n","import Box from \"@material-ui/core/Box\";\nimport * as React from \"react\";\nimport { FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport UndoIcon from \"@material-ui/icons/Undo\";\nimport RedoIcon from \"@material-ui/icons/Redo\";\nimport { Tooltip } from \"@material-ui/core\";\n\nexport const FormToolbarEditorButtons = (props: {\n fmFormRenderProps: FmFormRenderProps;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n return (\n <>\n fmFormRenderProps.submit()}\n disabled={\n fmFormRenderProps.isSubmitting || fmFormRenderProps.isDirty !== true\n }\n >\n Save\n \n \n \n
\n fmFormRenderProps.undo()}\n disabled={\n fmFormRenderProps.isSubmitting ||\n !fmFormRenderProps.isUndoAvailable\n }\n >\n \n \n
\n
\n \n \n
\n fmFormRenderProps.redo()}\n disabled={\n fmFormRenderProps.isSubmitting ||\n !fmFormRenderProps.isRedoAvailable\n }\n >\n \n {\" \"}\n
\n
\n \n );\n};\n","import * as React from \"react\";\n\ninterface HiderProps {\n hidden: boolean;\n // unomunt = true means unmount when hidden\n unmount?: boolean;\n}\n\nconst Hider: React.FunctionComponent = (props) => {\n if (props.hidden && props.unmount) return null;\n return (\n
\n {!props.hidden && props.children}\n
\n );\n};\nexport default Hider;\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n });\n});\nexport interface ToolbarTitleProps {}\n\nexport const ToolbarTitle: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n\nexport default ToolbarTitle;\n","import { useContext, useEffect } from \"react\";\nimport { FmFormContext } from \"./FmForm\";\n\nexport const useFormToolbar = (setFormToolbar: () => void) => {\n const fmFormContext = useContext(FmFormContext);\n useEffect(() => {\n setFormToolbar();\n }, [\n fmFormContext.isSubmitting,\n fmFormContext.formData,\n fmFormContext.isDirty,\n ]);\n};\n","import {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { GameSpec } from \"../../../domain/types\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { updateAbstract } from \"./manageGameAbstracts\";\n\nexport interface SaveGameRequest extends ApiRequest {\n id: string;\n gameSpec: GameSpec;\n name: string;\n}\n\nexport interface SaveGameResponse extends ValidatedApiResponse {\n id: string;\n}\n\nexport async function saveGame(\n request: SaveGameRequest\n): Promise {\n return makeCacheValidatedRequest(\n request,\n \"/api/save_game\"\n ).then((response) => {\n updateAbstract(request.id, (abstract) => {\n abstract.modified = response.timestamp;\n if (request.name) {\n // Name is changed only if supplied in request.\n abstract.name = request.name;\n }\n abstract.title = request.gameSpec.playSpec.title;\n abstract.subtitle = request.gameSpec.playSpec.subtitle;\n abstract.description = request.gameSpec.authorSpec.description;\n });\n return response;\n });\n}\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n body: {\n margin: \"0.25rem 0 0.25rem 0\",\n fontSize: theme.typography.body1.fontSize,\n },\n });\n});\nexport interface ExplanatoryNoteProps {}\n\nconst ExplanatoryNote: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return
{props.children}
;\n};\nexport default ExplanatoryNote;\n","import { SpellIcon } from \"../components/icons/SpellIcon\";\nimport * as React from \"react\";\nimport { ComputeIcon } from \"../components/icons/ComputeIcon\";\nimport { TwistIcon } from \"../components/icons/TwistIcon\";\n\nexport interface UserGameSettings {\n modifiedtime: Date;\n templategameid: string;\n hiddenwords: string[];\n extrawords: string[];\n}\n\nexport interface UserProfile {\n modifiedtime?: Date; // Optional so it doesn't need to be sent in server requests\n initials: string;\n displayName: string;\n isSuperAdmin?: boolean;\n}\n\nexport type GameType = \"s\" | \"c\" | \"t\";\nexport const getGameTypeLabel = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return \"Spell\";\n case \"c\":\n return \"Compute\";\n case \"t\":\n return \"Twist\";\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport const getGameTypeIcon = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return React.createElement(SpellIcon, null);\n case \"c\":\n return React.createElement(ComputeIcon, null);\n case \"t\":\n return React.createElement(TwistIcon, null);\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport const gameTypeHasAnswers = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return true;\n case \"c\":\n return false;\n case \"t\":\n return true;\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport const gameTypeUsesMenuRestart = (gameType: GameType) => {\n switch (gameType) {\n case \"s\":\n return true;\n case \"c\":\n return false;\n case \"t\":\n return true;\n }\n throw new Error(\"Invalid gametype:\" + gameType);\n};\n\nexport interface GameSpec {\n playSpec: PlaySpec;\n authorSpec: AuthorSpec;\n}\n\nexport enum AutoScoringMethod {\n Slow = \"s\",\n Medium = \"m\",\n Fast = \"f\",\n}\nexport interface AuthorSpec {\n autoScoring: boolean;\n autoScoringMethod: AutoScoringMethod;\n description: string;\n}\n// GameRecord is the layout in the database.\n// Edited games are saved in Draft.\n// Publishing copies Draft to Prod.\n// We keep name unique in the database.\nexport interface GameRecord {\n gameType: GameType;\n draft: GameSpec;\n prod: GameSpec;\n}\n\nexport interface PlaySpec {\n title: string;\n subtitle: string;\n levels: Array;\n rulesPrologue: string;\n answerKey: string;\n}\n\nexport interface Level {\n name: string;\n score: number; // min score for this level\n}\n\nexport const getLevelFromScore = (levels: Array, score: number) => {\n const reverseIndex = [...levels]\n .reverse()\n .findIndex((level) => (level.score ?? 0) <= score);\n return levels[levels.length - 1 - reverseIndex];\n};\n\n// g = game, p=progress\nexport type GameRefType = \"g\" | \"p\";\n\nexport interface GameRef {\n id: string; // key into either game collection or progess collection\n refType: GameRefType;\n}\n","import * as React from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"./dialogTools/DialogManager\";\nimport { InfoDialogBase } from \"./dialogTools/InfoDialog\";\nimport SettingDescription from \"./SettingDescription\";\nimport SettingHeader from \"./SettingHeader\";\nimport SettingsContainer from \"./SettingsContainer\";\n\nconst MyHelp = () => {\n return (\n \n Getting Help\n \n Sorry. There is no help for this page. If there is help for the page you\n are viewing, then it will appear here when you click \"HELP\".\n \n \n );\n};\n\nconst helpPages: Record = {\n home: ,\n};\n\n// Look for the active help item with the highest instanceId.\ninterface HelpItem {\n key: string;\n isActive: boolean;\n}\n// record key is the instanceId\nconst helpItems: Record = Object.create(null);\nlet helpInstanceId = 0;\nfunction getNextHelpInstanceId() {\n helpInstanceId++;\n return helpInstanceId;\n}\nexport const useHelp = (\n key: string,\n helpElement: JSX.Element,\n isActive: boolean\n) => {\n // Set current of myHelpInstanceIdRef the first time only.\n // That way it will have the helpInstanceId for this instance of the component.\n const myHelpInstanceIdRef = useRef(getNextHelpInstanceId());\n\n if (helpItems[myHelpInstanceIdRef.current]) {\n helpItems[myHelpInstanceIdRef.current].isActive = isActive;\n }\n\n // register the help element\n helpPages[key] = helpElement;\n useEffect(() => {\n // register instance\n helpItems[myHelpInstanceIdRef.current] = { key, isActive };\n return () => {\n // de-register instance\n delete helpItems[myHelpInstanceIdRef.current];\n };\n }, []);\n};\n\nconst getHighestActiveHelpKey = () => {\n const id = Object.keys(helpItems).reduce(\n (largestActiveId: number, instanceIdText: string) => {\n const instanceId = Number(instanceIdText);\n const item = helpItems[instanceId];\n if (item.isActive && instanceId > largestActiveId) {\n largestActiveId = instanceId;\n }\n return largestActiveId;\n },\n -1\n );\n return helpItems[id]?.key;\n};\n\nexport interface HelpDialogProps {}\nexport let getWordsDialogInternal: Dialog;\nexport const openHelpDialog = (props: HelpDialogProps) => {\n if (!getWordsDialogInternal) {\n getWordsDialogInternal = makeHelpDialogComponent();\n }\n return getDialogMethods().open(getWordsDialogInternal, props);\n};\n\nexport const makeHelpDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n let helpKey = getHighestActiveHelpKey();\n return (\n {\n dialogRenderProps.close(false, undefined);\n }}\n open={true}\n title={`Help ${helpKey}`}\n >\n {helpPages[helpKey] ?? \"No help available.\"}\n \n );\n },\n });\n};\n","import { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n margin: \"1rem 0 1rem 0\",\n },\n });\n});\ninterface SettingSubheaderProps {}\n\nconst SettingSubheader: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n return (\n \n {props.children}\n \n );\n};\n\nexport default SettingSubheader;\n","import * as React from \"react\";\n\ninterface SettingDescriptionProps {}\nconst Emphasize: React.FunctionComponent = (props) => {\n return {props.children} ;\n};\nexport default Emphasize;\n","import { Box } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport {\n MildGuidingButton,\n StrongGuidingButton,\n} from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport ExplanatoryNote from \"../../../../../components/ExplanatoryNote\";\nimport Hider from \"../../../../../components/Hider\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport {\n GameType,\n gameTypeHasAnswers,\n getGameTypeLabel,\n} from \"../../../../../domain/types\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { CommonFormData } from \"../editorTypes\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport RedoIcon from \"@material-ui/icons/Redo\";\nimport UndoIcon from \"@material-ui/icons/Undo\";\nimport SettingsContainer from \"../../../../../components/SettingsContainer\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport Emphasize from \"../../../../../components/Emphasize\";\n\nconst navHelp = (gameType: GameType) => (\n <>\n At the top-right of this page is a solid yellow button that looks like this:\n \n \n Choose {gameType === \"s\" ? \"Words\" : \"Challenges\"}\n \n \n Click it. To create a game, navigate back and forth through the game editor\n pages using the navigation buttons at the top. The forward buttons are solid\n yellow, and the backwards buttons are outlined, like this:\n \n Name Game\n \n There is no backwards button on this page, since it is the first page in the\n game editor.\n \n);\n\nconst EditNameGameTabInternal = (props: {\n formData: CommonFormData;\n showAnswerKey: boolean;\n gameType: GameType;\n isActive: boolean;\n}) => {\n const { formData } = props;\n useHelp(\"EditNameGameTab\", , props.isActive);\n return (\n \n );\n};\n\nexport const EditNameGameTab = React.memo(\n EditNameGameTabInternal,\n (prevProps, nextProps) => {\n if (prevProps.isActive !== nextProps.isActive) return false;\n if (prevProps.formData.name !== nextProps.formData.name) return false;\n if (prevProps.formData.title !== nextProps.formData.title) return false;\n if (prevProps.formData.subtitle !== nextProps.formData.subtitle)\n return false;\n if (prevProps.formData.answerKey !== nextProps.formData.answerKey)\n return false;\n if (prevProps.formData.isTemplateGame !== nextProps.formData.isTemplateGame)\n return false;\n return true;\n }\n);\n\nconst MyHelp = () => {\n return (\n \n Name Game\n Navigating Between Editor Tabs\n {navHelp}\n \n\n Name\n \n The name will be part of the game URL, making it easier for you to\n differentiate between URLs. The name must consist entirely of letters,\n digits, underscores, and dashes (no spaces, because it is part of a\n URL). This allows the name to be easily read in URLs, so that you can\n identify the game to which a URL refers.\n \n\n Title\n \n The title will appear at the top of the game.\n \n\n Subtitle\n \n The subtitle will appear just below the title. It is optional.\n \n\n Description\n \n The description lets you document information about a game. It is not\n shown to players. It is optional.\n \n\n Answer Key\n \n Some games do not have an answer key. Players can use the answer key to\n unlock the answers. It lets users see the words they missed. Case\n doesn't matter. Don't share it until you want them to know all of the\n answers.\n \n\n Undo and Redo\n \n While editing a game you can undo and redo changes, using the buttons{\" \"}\n \n and . If you leave and then return to the editor, you will\n not be able to undo or redo changes made previously.\n \n \n );\n};\n\nexport const SaveUndoRedoHelp = () => {\n return (\n <>\n Save\n \n Changes you make to the game while editing are not saved automatically.\n You must press SAVE.\n \n Undo and Redo\n \n While editing a game you can undo and redo changes, using the buttons{\" \"}\n \n and . If you leave and then return to the editor, you will\n not be able to undo or redo changes made previously.\n \n \n );\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeRequest } from \"../../../http/http\";\n\ninterface GetConfigurationRequest {}\n\ninterface GetConfigurationResponse extends ApiResponseHeader {\n gameUrlPattern: string;\n recaptchaSiteKey: string;\n}\n\nasync function getConfigurationInternal(\n request: GetConfigurationRequest\n): Promise {\n return makeRequest(request, \"/api/get_configuration\");\n}\n\ninterface Configuration {\n gameUrlPattern: string;\n recaptchaSiteKey: string;\n}\n\nlet configuration: Configuration;\n\nexport async function getConfiguration(): Promise {\n if (configuration) return configuration;\n const response = await getConfigurationInternal({});\n configuration = {\n gameUrlPattern: response.gameUrlPattern,\n recaptchaSiteKey: response.recaptchaSiteKey,\n };\n return configuration;\n}\n","import { getConfiguration } from \"../app/author/requests/getConfiguration\";\nimport { GameType, getGameTypeLabel } from \"./types\";\n\nexport const getGameUrl = async (\n gameType: GameType,\n gameId: string,\n gameName: string\n) => {\n const configuration = await getConfiguration();\n const prefix = configuration.gameUrlPattern\n ? configuration.gameUrlPattern.replace(\n \"GAME\",\n getGameTypeLabel(gameType).toLowerCase()\n )\n : \"\";\n return `${prefix}/run/${gameId}?name=${gameName}`;\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { updateAbstract } from \"./manageGameAbstracts\";\nimport { GameType } from \"../../../domain/types\";\n\nexport interface PublishGameRequest {\n id: string;\n gameType: GameType;\n}\n\nexport interface PublishGameResponse extends ApiResponseHeader {}\n\nexport async function publishGame(\n request: PublishGameRequest\n): Promise {\n return makeCacheValidatedRequest(request, \"/api/publish_game\").then(\n (response) => {\n updateAbstract(request.id, (abstract) => {\n abstract.published = response.timestamp;\n });\n return response;\n }\n );\n}\n","import * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { busyPromise } from \"../../../../../components/BusySpinner\";\nimport { PrimaryButton, SubtleButton } from \"../../../../../components/buttons\";\nimport ExplanatoryNote from \"../../../../../components/ExplanatoryNote\";\nimport Hider from \"../../../../../components/Hider\";\nimport {\n notifyError,\n notifySuccess,\n} from \"../../../../../components/NotificationManager\";\nimport { PageContainer } from \"../../../../../components/PageContainer\";\nimport PageIntro from \"../../../../../components/PageIntro\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { getGameUrl } from \"../../../../../domain/gameUrl\";\nimport { GameType } from \"../../../../../domain/types\";\nimport { publishGame } from \"../../../requests/publishGame\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport { CommonFormData } from \"../editorTypes\";\n\nexport const handlePublish = (\n isDirty: boolean,\n gameId: string,\n gameType: GameType,\n setIsPublished: () => void\n) => {\n if (isDirty) {\n notifyError(\"Please save your changes before publishing.\");\n return;\n }\n busyPromise(publishGame({ id: gameId, gameType }))\n .then((r) => {\n setIsPublished();\n notifySuccess(\"Your game is published.\");\n })\n .catch((error) => {\n notifyError(error.message);\n });\n};\n\nconst EditPublishTabInternal = (props: {\n isDirty: boolean;\n isSubmitting: boolean;\n gameId: string;\n gameName: string;\n gameType: GameType;\n isActive: boolean;\n formData: CommonFormData;\n setIsPublished: () => void;\n}) => {\n useHelp(\"EditPublishTab\", , props.isActive);\n const { isDirty, isSubmitting, gameId, gameName, formData } = props;\n const [gameUrl, setGameUrl] = useState(\"\");\n\n useEffect(() => {\n getGameUrl(props.gameType, gameId, gameName).then((url) => setGameUrl(url));\n }, [gameName]);\n\n return (\n \n );\n};\n\nexport const EditPublishTab = React.memo(\n EditPublishTabInternal,\n (prevProps, nextProps) => {\n if (prevProps.isActive !== nextProps.isActive) return false;\n if (prevProps.gameId !== nextProps.gameId) return false;\n if (prevProps.gameName !== nextProps.gameName) return false;\n if (prevProps.isDirty !== nextProps.isDirty) return false;\n if (prevProps.isSubmitting !== nextProps.isSubmitting) return false;\n if (prevProps.formData.isPublished !== nextProps.formData.isPublished)\n return false;\n return true;\n }\n);\n\nconst MyHelp = () => {\n return (\n <>\n Publish\n How Can I Test a Game?\n \n First, publish it. Then click PLAY GAME.\n \n \n How Can I Allow Others to Play a Game?\n \n \n First, click COPY GAME URL TO CLIPBOARD. Then share the URL by posting\n it on a website, send it in email, etc.\n \n \n How Can I Prevent Others from Playing a Published Game?\n \n \n You'll need to delete the game, which puts it in the trash. When you\n delete it from the trash, it will be permanently deleted. No one will be\n able to play the game or see game progress. Permanent deletion is not\n reversible.\n \n \n );\n};\n","import Paper from \"@material-ui/core/Paper\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\n\nexport interface TipProps {\n children: JSX.Element;\n}\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n tip: {\n margin: \"0.25rem\",\n padding: \"0.25rem\",\n background: theme.palette.secondary.light,\n },\n });\n});\n\nexport const Tip: React.FunctionComponent = (props: TipProps) => {\n const classes = useStyles();\n return Tip: {props.children};\n};\n","import { PlaySpec, GameType, AuthorSpec } from \"./types\";\n\nexport interface Answer {\n word: string;\n score: number;\n}\n\nexport interface OperationDomain {\n // The lhs is the text entered by the author to describe the range of the Lhs operands.\n lhs: string;\n // The rhs is the text entered by the author to describe the range of the Rhs operands.\n rhs: string;\n}\n\nexport const NewOperationDomain = (): OperationDomain => {\n return {\n lhs: \"\",\n rhs: \"\",\n };\n};\n\nexport interface ComputePlaySpec extends PlaySpec {\n add: OperationDomain;\n sub: OperationDomain;\n mul: OperationDomain;\n div: OperationDomain;\n // timeLimit is the number of seconds until the game ends.\n // If undefined, then there is no time limit.\n timeLimit: number;\n // ChallengeCount is the number of challenges in a game.\n challengeCount: number;\n // MustSolve true means each challenge must be solved before the next challenge is presented.\n mustSolve: boolean;\n}\n\n// GameAuthorSpec has the data needed to author a game\nexport interface ComputeAuthorSpec extends AuthorSpec {}\n\nexport interface ComputeSpec {\n playSpec: ComputePlaySpec;\n authorSpec: ComputeAuthorSpec;\n}\n\n// ComputeRecord is the layout in the database.\n// Edited games are saved in Draft.\n// Publishing copies Draft to Prod.\n// We keep name unique in the database.\nexport interface ComputeRecord {\n gameType: GameType;\n draft: ComputeSpec;\n prod: ComputeSpec;\n}\n\nexport enum Op {\n Add = \"+\",\n Sub = \"-\",\n Mul = \"*\",\n Div = \"/\",\n}\n\nexport const getOpChar = (op: Op) => {\n switch (op) {\n case Op.Add:\n return \"+\";\n case Op.Mul:\n return \"×\";\n case Op.Div:\n return \"÷\";\n case Op.Sub:\n return \"-\";\n }\n};\n\n// Challenge is a problem.\nexport interface Challenge {\n op: Op;\n lhs: number;\n rhs: number;\n}\n\n// Chaser is short for ChallengeAnswer.\n// It holds the challenge and the player's answer (which could be right or wrong).\n// Skipped is true if the user skipped the challenge.\nexport interface Chaser {\n challenge: Challenge;\n answer: number;\n skipped: boolean;\n}\n\nexport interface ComputeProgress {\n chasers: Chaser[];\n elapsedSeconds: number;\n}\n\n// solve returns the correct answer for a challenge.\nexport function solve(c: Challenge) {\n switch (c.op) {\n case Op.Mul:\n return c.lhs * c.rhs;\n case Op.Div:\n return c.lhs / c.rhs;\n case Op.Add:\n return c.lhs + c.rhs;\n case Op.Sub:\n return c.lhs - c.rhs;\n }\n}\n\nexport interface OperandRange {\n start: number;\n end: number;\n}\nconst validSingle = new RegExp(String.raw`^[0-9]+$`);\nconst validRange = new RegExp(String.raw`^[0-9]+-[0-9]+$`);\nconst hyphenWithWhitespace = new RegExp(String.raw`\\s*-\\s*`, \"g\");\nconst whitespace = new RegExp(String.raw`\\s+`, \"g\");\n\n// Compile compiles a text list of possible operand values into an OperandRange structure.\n// Lists consist of one or more comma-separated or whitespace-separated tokens.\n// Each token may be a decimal number, or two decimal numbers separated by a asterisk.\n// Asterisk-separated numbers translate to ranges that start with the smaller number and end with the larger,\n// meaning that order doesn't matter. Specifying the same start and end is identical to specifying a single number.\n// Decimal numbers may not exceed 1000.\n// There are equivalent:\n// * 1-2,4,6-10\n// * 1 - 2,4 6-10\n// * 1-2 4 6-10\n\n// Generously interpret operand ranges:\n// * Ignore duplicates, including overlapping ranges\n// * Allow ranges to go backwards\n// * Preserve range list as typed by user.\n\nfunction compile(t: string): OperandRange[] {\n // * 1 - 2,4 6-10\n // Replace asterisk surrounded by whitespace with just a hyphen\n // After trimming whitespace\n let s = t.trim().replace(hyphenWithWhitespace, \"-\");\n // * 1-2,4 6-10\n // Replace whitespace with a single comma\n s = s.replace(whitespace, \",\");\n // * 1-2,4,6-10\n const tokens = s.split(\",\");\n const r: OperandRange[] = [];\n for (let i = 0; i < tokens.length; i++) {\n if (validSingle.test(tokens[i])) {\n const n = convertOperandToNumber(tokens[i]);\n r.push({ start: n, end: n });\n } else if (validRange.test(tokens[i])) {\n const ts = tokens[i].split(\"-\");\n const n = convertOperandToNumber(ts[0]);\n const m = convertOperandToNumber(ts[1]);\n if (n <= m) {\n r.push({ start: n, end: m });\n } else {\n r.push({ start: m, end: n });\n }\n }\n }\n return r;\n}\n\nfunction convertOperandToNumber(s: string) {\n const n = Number(s);\n if (n > 1000) {\n throw new Error(\"Range value is greater than 1000.\");\n }\n return n;\n}\n\nexport function createAllChallenges(playSpec: ComputePlaySpec) {\n const challenges: Challenge[] = [];\n if (playSpec.add) {\n challenges.push(...createChallenges(Op.Add, playSpec.add));\n }\n if (playSpec.sub) {\n challenges.push(...createChallenges(Op.Sub, playSpec.sub));\n }\n if (playSpec.mul) {\n challenges.push(...createChallenges(Op.Mul, playSpec.mul));\n }\n if (playSpec.div) {\n challenges.push(...createChallenges(Op.Div, playSpec.div));\n }\n return challenges;\n}\n\n// createChallenges returns an array of all of the challenges given an operation and a domain.\nexport function createChallenges(op: Op, od: OperationDomain) {\n const lhs = compile(od.lhs);\n const rhs = compile(od.rhs);\n const challenges: Record = Object.create(null);\n lhs.forEach((lhsRange) => {\n for (let loperand = lhsRange.start; loperand <= lhsRange.end; loperand++) {\n rhs.forEach((rhsRange) => {\n for (\n let roperand = rhsRange.start;\n roperand <= rhsRange.end;\n roperand++\n ) {\n const challenge: Challenge = { op, lhs: loperand, rhs: roperand };\n switch (op) {\n case Op.Div:\n if (solve(challenge) % 1 !== 0) continue;\n break;\n case Op.Sub:\n if (solve(challenge) < 0) continue;\n break;\n }\n challenges[op + loperand + \"|\" + roperand] = challenge;\n }\n });\n }\n });\n return Object.values(challenges);\n}\n","import { Box, Container } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport Hider from \"../../../components/Hider\";\nimport {\n ComputePlaySpec,\n createChallenges,\n Op,\n} from \"../../../domain/compute_types\";\nimport { pluralize } from \"../../../utilities\";\nimport { GameInfo } from \"./ComputeGameComponent\";\n\nexport interface ComputeRulesComponentProps {\n playSpec: ComputePlaySpec;\n gameInfo: GameInfo;\n}\nexport const ComputeRulesComponent = (props: ComputeRulesComponentProps) => {\n const { playSpec, gameInfo } = props;\n const rulesPrologue = playSpec.rulesPrologue;\n const rulesPrologueComponent = !rulesPrologue ? null : (\n {rulesPrologue}\n );\n\n const opList: { opLabel: string; opCount: number }[] = [];\n if (playSpec.add) {\n const addChallenges = createChallenges(Op.Add, playSpec.add);\n if (addChallenges.length > 0)\n opList.push({ opLabel: \"addition\", opCount: addChallenges.length });\n }\n if (playSpec.sub) {\n const subChallenges = createChallenges(Op.Sub, playSpec.sub);\n if (subChallenges.length > 0)\n opList.push({ opLabel: \"subtraction\", opCount: subChallenges.length });\n }\n if (playSpec.mul) {\n const mulChallenges = createChallenges(Op.Mul, playSpec.mul);\n if (mulChallenges.length > 0)\n opList.push({ opLabel: \"multiplication\", opCount: mulChallenges.length });\n }\n if (playSpec.div) {\n const divChallenges = createChallenges(Op.Div, playSpec.div);\n if (divChallenges.length > 0)\n opList.push({ opLabel: \"division\", opCount: divChallenges.length });\n }\n let opsText: string;\n if (opList.length === 1) {\n opsText = `${opList[0].opCount} ${opList[0].opLabel}`;\n } else if (opList.length === 2) {\n opsText =\n `${opList[0].opCount} ${opList[0].opLabel}` +\n \" and \" +\n `${opList[1].opCount} ${opList[1].opLabel}`;\n } else if (opList.length === 3) {\n opsText =\n `${opList[0].opCount} ${opList[0].opLabel}` +\n \", \" +\n `${opList[1].opCount} ${opList[1].opLabel}` +\n \", and \" +\n `${opList[2].opCount} ${opList[2].opLabel}`;\n } else if (opList.length === 4) {\n opsText =\n `${opList[0].opCount} ${opList[0].opLabel}` +\n \", \" +\n `${opList[1].opCount} ${opList[1].opLabel}` +\n \", \" +\n `${opList[2].opCount} ${opList[2].opLabel}` +\n \", and \" +\n `${opList[3].opCount} ${opList[3].opLabel}`;\n }\n\n return (\n \n {rulesPrologueComponent}\n \n \n

The following rules apply to this game:

\n
    \n
  • \n {`The game has ${pluralize(\n playSpec.challengeCount,\n \"challenge\"\n )} worth a total of ${pluralize(\n playSpec.challengeCount,\n \"point\"\n )}.`}\n {gameInfo.highestLevel.score >= gameInfo.maxPoints\n ? \"\"\n : \" You don't need to solve all of the challenges to achieve the top level.\"}\n
  • \n
  • \n The {pluralize(playSpec.challengeCount, \"challenge\")} are randomly\n selected from {opsText} problems.\n
  • \n \n \n \n
  • \n You can play as many times as you want by clicking PLAY AGAIN.\n
  • \n
\n
\n \n \n The game levels and the number of points needed to reach each level are:{\" \"}\n {props.playSpec.levels.map((level, index) => (\n \n {index > 0 ? \", \" : \"\"}\n {level.name} {level.score}\n \n ))}\n .\n \n \n \n );\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FormData } from \"./ComputeEditPage\";\nimport Hider from \"../../../../../components/Hider\";\nimport { ComputeRulesComponent } from \"../../../../compute/components/ComputeRulesComponent\";\nimport { ComputePlaySpec } from \"../../../../../domain/compute_types\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\n\nexport const ComputeEditRulesPrologueTab = (props: {\n rulesPrologue: string;\n isActive: boolean;\n playSpec: ComputePlaySpec;\n}) => {\n return (\n \n );\n};\n","import * as React from \"react\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\n\nexport const AutoScoringHelp = () => {\n return (\n <>\n Auto Scoring\n \n If auto scoring is disabled, you need to manually set the number of\n points for each level. If enabled, the score for each level is computed\n for you, according to the auto scoring method. The \"faster\" the method,\n the faster the player will reach higher achievement levels.\n \n Auto Scoring Method Details\n \n For all methods the lowest level is reached with zero points, and the\n highest is reached with the high score.\n
    \n
  • \n Slow: The second level score is 2/3 of the high score. The\n remaining levels (if any) are spread evenly between the second level\n and the penultimate level. Use this method when most players are\n expected to achieve a high score.\n
  • \n
  • \n Medium: The levelscare spread evenly between the lowest level\n and the highest level.\n
  • \n
  • \n Fast: The penultimate level score is 2/3 of the high score.\n The remaining levels (if any) are spread evenly between the lowest\n level and the penultimate level. Reaching the penultimate level is\n often worthy of high praise!\n
  • \n
\n
\n \n );\n};\n","import { Draft } from \"immer\";\nimport * as React from \"react\";\nimport { useContext } from \"react\";\nimport { PrimaryButton } from \"../components/buttons\";\nimport { FmFormContext, FmFormRenderProps } from \"./FmForm\";\nimport {\n DragDropContext,\n DropResult,\n ResponderProvided,\n Droppable,\n Draggable,\n} from \"react-beautiful-dnd\";\nexport interface FmListRenderProps {\n value: TItem;\n index: number;\n values: TItem[];\n sortedIndex: number;\n setFormDataValue: (value: TItem) => void;\n itemAction: (action: string) => void;\n removeItem: () => void;\n fmFormRenderProps: FmFormRenderProps;\n}\n\nexport interface ItemActionRenderProps {\n action: string;\n item: TItem;\n items: TItem[];\n position: number;\n setFormData: (\n mutator: (formData: Draft) => void | TFormData\n ) => TFormData;\n}\n\nexport interface FmListProps {\n name: keyof TFormData & string;\n sortComparer?: (a: TItem, b: TItem) => number;\n itemAction?: (renderProps: ItemActionRenderProps) => void;\n showAddButton?: boolean;\n children: (\n fmListItemProps: FmListRenderProps\n ) => JSX.Element;\n minItems?: number;\n maxItems?: number;\n reorder?: (\n draftFormData: Draft,\n originalIndex: number,\n newIndex: number\n ) => void;\n addButtonLabel?: string;\n}\n\nexport const FmList = (\n props: FmListProps\n) => {\n const fmFormRenderProps: FmFormRenderProps = useContext(\n FmFormContext\n );\n const { name, sortComparer, itemAction, minItems, maxItems } = props;\n const { formData, setFormData } = fmFormRenderProps;\n const items = (formData[name] as unknown) as TItem[];\n const unsortedValues = items.map((value, index) => {\n return { value, index };\n });\n // Sort in order rendered so that rendered component knows order\n const values = sortComparer\n ? [...unsortedValues].sort((a, b) => sortComparer(a.value, b.value))\n : unsortedValues;\n let renderItems = values.map((wrappedValue, index, wrappedValues) => {\n const fmListRenderProps: FmListRenderProps = {\n fmFormRenderProps,\n value: wrappedValue.value,\n index: wrappedValue.index,\n values: wrappedValues.map((wrappedValue) => wrappedValue.value),\n sortedIndex: index,\n setFormDataValue: (value: TItem) => {\n setFormData((formData) => {\n (formData as any)[name][wrappedValue.index] = value;\n });\n },\n itemAction: (action: string) => {\n if (action === \"add\" && items.length < (maxItems ?? 25))\n itemAction({\n action,\n item: wrappedValue.value,\n items: values.map((value) => value.value),\n position: wrappedValue.index,\n setFormData,\n });\n },\n removeItem: () => {\n if (items.length <= (minItems ?? 0)) return;\n setFormData((formData) => {\n (formData as any)[name].splice(index, 1);\n });\n },\n };\n return {\n value: wrappedValue.value,\n element: props.children(fmListRenderProps),\n };\n });\n\n const onDragEnd = (result: DropResult, provided: ResponderProvided) => {\n if (!result.destination) {\n return;\n }\n fmFormRenderProps.setFormData((draftFormData) => {\n props.reorder(\n draftFormData,\n result.source.index,\n result.destination.index\n );\n });\n };\n\n return (\n \n {props.showAddButton && (\n {\n if (items.length < (maxItems ?? 25))\n itemAction({\n action: \"add\",\n item: undefined, // because we are adding to top\n items: values.map((value) => value.value),\n position: -1,\n setFormData,\n });\n }}\n >\n {props.addButtonLabel ?? \"Add\"}\n \n )}\n \n \n {(providedDroppable, snapshot) => (\n \n {providedDroppable.placeholder}\n {renderItems.map((renderItem, index) => (\n \n {(provided, snapshot) => {\n return (\n \n {renderItem.element}\n \n );\n }}\n \n ))}\n \n )}\n \n \n \n );\n};\n","import Box from \"@material-ui/core/Box\";\nimport Grid from \"@material-ui/core/Grid\";\nimport Grow from \"@material-ui/core/Grow\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport Paper from \"@material-ui/core/Paper\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport TextField from \"@material-ui/core/TextField\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\nimport AddLevelIcon from \"@material-ui/icons/AddCircle\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport * as React from \"react\";\nimport { useRef } from \"react\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport {\n FmFieldErrorCode,\n FmNumberField,\n FmSwitchField,\n FmDiscreteSliderField,\n} from \"../../../../../formManager/FmField\";\nimport { FmList, FmListRenderProps } from \"../../../../../formManager/FmList\";\nimport { serialId } from \"../../../../../utilities\";\nimport { FormLevel } from \"../editorTypes\";\nimport { AutoScoringMethod } from \"../../../../../domain/types\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\n\nconst useStyles = makeStyles(() => {\n return createStyles({\n tile: {\n border: \"solid\",\n marginBottom: \"0.25rem\",\n paddingLeft: \"0.5rem\",\n paddingRight: \"0.5rem\",\n },\n nameField: { width: \"12rem\", marginRight: \"0.5rem\" },\n scoreField: { width: \"4rem\" },\n slider: {\n marginLeft: \"2rem\",\n width: \"10rem\",\n },\n });\n});\n\nexport interface LadderProps {\n levels: FormLevel[];\n highScore: number;\n autoScoring: boolean;\n autoScoringMethod: AutoScoringMethod;\n}\nconst LadderInternal = (props: LadderProps) => {\n const classes = useStyles();\n const { highScore, autoScoring } = props;\n const previousNameIndex = useRef(0);\n const highestRenderedIdRef = useRef(-1);\n return (\n \n \n \n High Score {highScore}\n \n \n \n \n \n \n {\n // add is the only action\n const { item, items, position, setFormData } = itemActionRenderProps;\n // Get a unique level name\n const newNameBase = \"New Level \";\n let nameCandidate: string;\n for (let i = previousNameIndex.current + 1; true; i++) {\n nameCandidate = newNameBase + i.toString();\n if (\n undefined === items.find((level) => level.name === nameCandidate)\n ) {\n previousNameIndex.current = i;\n break;\n }\n }\n const level: FormLevel = {\n name: nameCandidate,\n score: item.score + 1,\n id: serialId(),\n };\n setFormData((draftFormData) => {\n draftFormData.levels = [\n ...draftFormData.levels.slice(0, position + 1),\n level,\n ...draftFormData.levels.slice(position + 1),\n ];\n });\n }}\n sortComparer={(a, b) => a.score - b.score}\n >\n {(\n fmListRenderProps: FmListRenderProps<\n { [\"levels\"]: FormLevel[] },\n FormLevel\n >\n ) => {\n const values = fmListRenderProps.values;\n const valuesLength = values.length;\n const sortedIndex = fmListRenderProps.sortedIndex;\n const scoreAbove =\n sortedIndex <= 0 ? -1 : values[sortedIndex - 1].score;\n const scoreBelow =\n sortedIndex >= valuesLength - 1\n ? Number.MAX_VALUE\n : values[sortedIndex + 1].score;\n const highestRenderedId = highestRenderedIdRef.current;\n if (fmListRenderProps.value.id > highestRenderedId)\n highestRenderedIdRef.current = fmListRenderProps.value.id;\n return (\n fmListRenderProps.itemAction(\"add\")}\n scoreBelow={scoreBelow}\n scoreAbove={scoreAbove}\n highestRenderedId={highestRenderedId}\n scoreDisabled={autoScoring || fmListRenderProps.sortedIndex === 0}\n deleteDisabled={fmListRenderProps.sortedIndex === 0}\n autoScoring={autoScoring}\n firstTile={fmListRenderProps.sortedIndex === 0}\n highScore={highScore}\n />\n );\n }}\n \n \n );\n};\n\nexport const Ladder = React.memo(LadderInternal, (prevProps, nextProps) => {\n if (prevProps.levels !== nextProps.levels) return false;\n if (\n prevProps.highScore !== nextProps.highScore ||\n prevProps.autoScoring !== nextProps.autoScoring\n )\n return false;\n return true;\n});\n\ninterface LevelTileProps {\n level: FormLevel;\n setValue: (level: FormLevel) => void;\n remove: () => void;\n addBelow: () => void;\n highestRenderedId: number;\n scoreAbove: number;\n scoreBelow: number;\n scoreDisabled: boolean;\n deleteDisabled: boolean;\n autoScoring: boolean;\n firstTile: boolean;\n highScore: number;\n}\nconst LevelTile = (props: LevelTileProps) => {\n const {\n level,\n setValue,\n remove,\n addBelow,\n scoreAbove,\n scoreBelow,\n highestRenderedId,\n scoreDisabled,\n deleteDisabled,\n autoScoring,\n firstTile,\n highScore,\n } = props;\n const classes = useStyles();\n const animate = level.id > highestRenderedId;\n\n const customErrorMessagesMax = {\n [FmFieldErrorCode.OverMax]: `The score for a level may not be greater than the high score, which currently is ${highScore}.`,\n };\n\n return (\n \n \n {\n setValue({\n name: event.currentTarget.value,\n score: level.score,\n id: level.id,\n });\n }}\n />\n {\n if (!scoreDisabled) return;\n if (firstTile) {\n notifyError(\"The score of the first level must be zero.\");\n return;\n }\n if (autoScoring) {\n notifyError(\n \"Turn auto scoring off to manually change the score at each level.\"\n );\n }\n }}\n >\n level.score,\n mutate: (value) => {\n setValue({\n score: value,\n name: level.name,\n id:\n level.score < scoreAbove || level.score > scoreBelow\n ? serialId()\n : level.id,\n });\n },\n }}\n labelText={\"Score\"}\n placeholderText={\"Score\"}\n />\n \n \n addBelow()}\n >\n \n \n \n \n {\n if (deleteDisabled) {\n notifyError(\n \"You cannot delete the first level. Also, the first level's score must be zero.\"\n );\n } else {\n remove();\n }\n }}\n >\n \n \n \n \n \n );\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport Hider from \"../../../../../components/Hider\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { AutoScoringHelp } from \"../../shared/components/AutoScoringHelp\";\nimport { Ladder } from \"../../shared/components/Ladder\";\nimport { FormData } from \"./ComputeEditPage\";\n\nconst ComputeEditScoringTabInternal = (props: {\n formData: FormData;\n isActive: boolean;\n}) => {\n useHelp(\"ComputeEditScoringTab\", , props.isActive);\n const { formData } = props;\n return (\n \n );\n};\n\nexport const ComputeEditScoringTab = React.memo(\n ComputeEditScoringTabInternal,\n (prevProps, nextProps) => {\n if (prevProps.isActive !== nextProps.isActive) return false;\n if (prevProps.formData.levels !== nextProps.formData.levels) return false;\n if (prevProps.formData.autoScoring !== nextProps.formData.autoScoring)\n return false;\n if (\n prevProps.formData.autoScoringMethod !==\n nextProps.formData.autoScoringMethod\n )\n return false;\n return true;\n }\n);\n\nconst MyHelp = () => {\n return (\n <>\n Create Scoring\n \n \n );\n};\n","import { Divider } from \"@material-ui/core\";\nimport FormControlLabel from \"@material-ui/core/FormControlLabel\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport Switch from \"@material-ui/core/Switch\";\nimport TextField from \"@material-ui/core/TextField\";\nimport { Draft } from \"immer\";\nimport * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport Emphasize from \"../../../../../components/Emphasize\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport Hider from \"../../../../../components/Hider\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport SettingsContainer from \"../../../../../components/SettingsContainer\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport {\n getOpChar,\n NewOperationDomain,\n Op,\n OperationDomain,\n} from \"../../../../../domain/compute_types\";\nimport {\n FmNumberField,\n FmSwitchField,\n} from \"../../../../../formManager/FmField\";\nimport { FormData } from \"./ComputeEditPage\";\n\nconst useStyles = makeStyles(() => {\n return createStyles({\n divider: {\n width: \"100%\",\n marginBottom: \"0.25rem\",\n },\n text: {\n margin: \"8px 1rem 8px 1rem\",\n },\n });\n});\n\n// const delegator = (v: T, setter: (v: T) => void) => {\n// return [v, setter];\n// };\n\nconst ComputeEditChallengesTabInternal = (props: {\n formData: FormData;\n setFormData: (\n mutator: (formData: Draft) => FormData | void\n ) => FormData;\n isActive: boolean;\n}) => {\n useHelp(\"ComputeEditChallengesTab\", , props.isActive);\n const { formData, setFormData } = props;\n return (\n \n );\n};\n\nexport const ComputeEditChallengesTab = React.memo(\n ComputeEditChallengesTabInternal,\n () => {\n return false;\n }\n);\n\nconst OpWidget = (props: {\n op: Op;\n opEnabled: boolean;\n domain: OperationDomain;\n enableDomain: (enabled: boolean) => void;\n setDomain: (mutator: (domain: OperationDomain) => void) => void;\n}) => {\n return (\n \n
\n {\n props.enableDomain(event.currentTarget.checked);\n }}\n />\n }\n label={\n \n {getOpChar(props.op)}\n \n }\n />\n
\n \n \n \n
\n
\n );\n};\n\nconst OperandRangeField = (props: {\n rangeText: string;\n labelText: string;\n setRangeText: (rangeText: string) => void;\n}) => {\n const classes = useStyles();\n return (\n {\n props.setRangeText(event.currentTarget.value);\n }}\n />\n );\n};\n\nconst MyHelp = () => {\n return (\n \n Chose Challenges\n Operations\n \n Enable between 1 and 4 operations:\n
    \n
  • Addition
  • \n
  • Subtraction
  • \n
  • Multiplication
  • \n
  • Division
  • \n
\n
\n \n For each operation you enable, you must specify the operands on the left\n side and right side. These are the Left Operand Value List and the Right\n Operand Value List. You can specify a range, such as \"1-10\", or a list,\n such as \"2, 4, 6, 8\". Or you may specify both ranges and lists (commas\n are optional). Examples:\n
    \n
  • \n 1-10Integers from 1 through 10\n
  • \n
  • \n 1 2 3 4 5 6 7 8 9 10Integers from 1 through\n 10\n
  • \n
  • \n 1-10 15 20 25Integers from 1 through 10 and\n multiples of 5 from 15 through 25\n
  • \n
\n
\n\n Challenges\n \n Cortex will build an internal list of all of the possible challenges\n (problems) that result in a non-negative integer. It will present those\n challenges in a random order, until either the time limit is exceeded or\n all challenges are answered. A challenge won't be repeated in the same\n game unless the number of possible challenges is less that the number of\n challenges configured for the game.\n \n \n The operations with more possible challenges will tend to be presented\n more often because of the method of random selection.\n \n\n Time Limit\n \n The game ends when the time limit is reached. If the time limit is set\n to zero, then the game will not end based on elapsed time.\n \n\n Number of Challenges\n \n This is the greatest number of challenges that will be presented within\n the time limit. If there is no time limit (that is, the time limit is\n set to zero), then the game ends only when the specified number of\n challenges have been presented.\n \n
\n );\n};\n","import { AutoScoringMethod } from \"../../../../domain/types\";\nimport { FormLevel } from \"./editorTypes\";\nimport { round } from \"../../../../utilities\";\n\nlet memokey_deriveLevelScores: string;\nexport const clearLevelScoresCache = () => {\n memokey_deriveLevelScores = undefined;\n};\nexport const deriveLevelScores = (dependencies: {\n levels: FormLevel[]; // this is mutated, but is also a dependency\n highScore: number;\n autoScoring: boolean;\n autoScoringMethod: AutoScoringMethod;\n}) => {\n const { autoScoring, highScore, levels } = dependencies;\n if (!autoScoring) return; // no need to mutate\n const memokey = JSON.stringify(dependencies);\n if (memokey === memokey_deriveLevelScores) return;\n memokey_deriveLevelScores = memokey;\n levels[0].score = 0;\n const highIndex = levels.length - 1;\n if (highIndex < 1) return;\n levels[highIndex].score = highScore;\n if (highIndex < 2) return;\n switch (dependencies.autoScoringMethod) {\n case AutoScoringMethod.Medium:\n const deltaLinear = highScore / highIndex;\n for (let index = 1; index < highIndex; index++) {\n levels[index].score = round(index * deltaLinear);\n }\n break;\n case AutoScoringMethod.Slow:\n const secondScore = highScore / 3;\n levels[1].score = round(secondScore);\n if (highIndex < 3) return;\n const deltaHard = secondScore / (highIndex - 1);\n for (let index = 2; index < highIndex; index++) {\n levels[index].score = round(index * deltaHard);\n }\n break;\n case AutoScoringMethod.Fast:\n default:\n const penultimateScore = (highScore * 2) / 3;\n levels[highIndex - 1].score = round(penultimateScore);\n if (highIndex < 3) return;\n const delta = penultimateScore / (highIndex - 1);\n for (let index = 1; index < highIndex - 1; index++) {\n levels[index].score = round(index * delta);\n }\n break;\n }\n};\n","import Box from \"@material-ui/core/Box\";\nimport * as React from \"react\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport { GameType } from \"../../../domain/types\";\nimport { FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { handlePublish } from \"../games/shared/components/EditPublishTab\";\nimport { CommonFormData } from \"../games/shared/editorTypes\";\n\nexport const FormToolbarPublishButton = (props: {\n fmFormRenderProps: FmFormRenderProps;\n gameId: string;\n gameType: GameType;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n\n return (\n <>\n \n handlePublish(\n fmFormRenderProps.isDirty,\n props.gameId,\n props.gameType,\n () =>\n fmFormRenderProps.setDerivedFormData((draftDerivedFormData) => {\n draftDerivedFormData.isPublished = true;\n })\n )\n }\n disabled={fmFormRenderProps.isSubmitting}\n >\n Publish\n \n \n \n );\n};\n","import { Toolbar } from \"@material-ui/core\";\nimport Container from \"@material-ui/core/Container\";\nimport NavigateBefore from \"@material-ui/icons/NavigateBefore\";\nimport NavigateNext from \"@material-ui/icons/NavigateNext\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport {\n MildGuidingButton,\n StrongGuidingButton,\n} from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { FormToolbarEditorButtons } from \"../../../components/FormToolbarEditorButtons\";\nimport Hider from \"../../../../../components/Hider\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport { Title } from \"../../../../../components/Title\";\nimport ToolbarTitle from \"../../../../../components/ToolbarTitle\";\nimport { GameAbstract } from \"../../../../../domain/serverContract\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport { useFormToolbar } from \"../../../../../formManager/useFormToolbar\";\nimport { getGame } from \"../../../requests/getGame\";\nimport { saveGame } from \"../../../requests/saveGame\";\nimport { round, serialId } from \"../../../../../utilities\";\nimport { EditNameGameTab } from \"../../shared/components/EditNameGameTab\";\nimport { EditPublishTab } from \"../../shared/components/EditPublishTab\";\nimport { CommonFormData, FormLevel } from \"../../shared/editorTypes\";\n\nimport { ComputeEditRulesPrologueTab } from \"./ComputeEditRulesPrologueTab\";\nimport { ComputeEditScoringTab } from \"./ComputeEditScoringTab\";\nimport { ComputeEditChallengesTab } from \"./ComputeEditChallengesTab\";\nimport {\n PlaySpec,\n AutoScoringMethod,\n GameType,\n} from \"../../../../../domain/types\";\nimport {\n ComputeRecord,\n ComputeAuthorSpec,\n ComputePlaySpec,\n OperationDomain,\n} from \"../../../../../domain/compute_types\";\nimport {\n clearLevelScoresCache,\n deriveLevelScores,\n} from \"../../shared/deriveLevelScores\";\nimport { FormToolbarPublishButton } from \"../../../components/FormToolbarPublishButton\";\n\nconst GAMETYPE: GameType = \"c\";\nexport interface FormData extends CommonFormData {\n add: OperationDomain;\n sub: OperationDomain;\n mul: OperationDomain;\n div: OperationDomain;\n // TimeLimit is the number of seconds until the game ends.\n // If undefined, then there is no time limit.\n timeLimit: number;\n // ChallengeCount is the number of challenges in a game.\n challengeCount: number;\n // MustSolve true means each challenge must be solved before the next challenge is presented.\n mustSolve: boolean;\n}\n\nconst tabNames = [\n \"Name Game\",\n \"Choose Challenges\",\n \"Create Scoring (optional)\",\n \"Write Rules (optional)\",\n \"Publish\",\n];\n\nconst tabNavNames = [\n \"Name Game\",\n \"Choose Challenges\",\n \"Create Scoring\",\n \"Write Rules\",\n \"Publish\",\n];\n\n// Build gamePlaySpec from formdata\nconst buildPlaySpec = (formData: FormData) => {\n const playSpec: PlaySpec = {\n answerKey: formData.answerKey,\n levels: formData.levels,\n subtitle: formData.subtitle,\n title: formData.title,\n rulesPrologue: formData.rulesPrologue,\n };\n const computePlaySpec: ComputePlaySpec = {\n ...playSpec,\n challengeCount: formData.challengeCount,\n mustSolve: formData.mustSolve,\n timeLimit: formData.timeLimit,\n add: formData.add,\n sub: formData.sub,\n mul: formData.mul,\n div: formData.div,\n };\n return computePlaySpec;\n};\n\nexport interface ComputeEditPageProps {\n setToolbar: (element: JSX.Element) => void;\n gameAbstract: GameAbstract;\n}\nexport const ComputeEditPage = (props: ComputeEditPageProps) => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const computePlaySpec = buildPlaySpec(formData);\n const authorSpec: ComputeAuthorSpec = {\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n description: formData.description,\n };\n return saveGame({\n id: formData.id,\n gameSpec: { playSpec: computePlaySpec, authorSpec },\n name:\n formData.name === fmFormRenderProps.cleanFormData.name\n ? undefined\n : formData.name,\n });\n };\n\n const getGameFromAbstract = async (\n gameAbstract: GameAbstract\n ): Promise => {\n const gameId = gameAbstract.id;\n return getGame({ id: gameId }).then((result) => {\n // blow away memo cache\n clearLevelScoresCache();\n\n const gameRecord = result.gameRecord as ComputeRecord;\n const { draft } = gameRecord;\n const name = gameAbstract.name;\n let initialLevels: FormLevel[] = [\n { name: \"Novice\", score: 0, id: serialId() },\n { name: \"Spectacular\", score: 1, id: serialId() },\n ];\n\n const commonFormData: CommonFormData = {\n fmFormDataVersion: 0,\n id: gameId,\n name,\n answerKey: draft.playSpec.answerKey ?? \"\",\n levels:\n draft.playSpec.levels?.map((level) => {\n return {\n name: level.name,\n score: level.score ?? 0,\n id: serialId(),\n };\n }) ?? initialLevels,\n rulesPrologue: draft.playSpec.rulesPrologue ?? \"\",\n subtitle: draft.playSpec.subtitle ?? \"\",\n title: draft.playSpec.title ?? \"\",\n autoScoring: draft.authorSpec.autoScoring ?? true,\n autoScoringMethod:\n draft.authorSpec.autoScoringMethod ?? AutoScoringMethod.Fast,\n description: draft.authorSpec.description ?? \"\",\n isTemplateGame: gameAbstract.template,\n isPublished: !!gameAbstract.published,\n };\n const formData: FormData = {\n ...commonFormData,\n challengeCount: draft.playSpec.challengeCount ?? 60,\n mustSolve: draft.playSpec.mustSolve ?? false,\n timeLimit: draft.playSpec.timeLimit ?? 60,\n add: draft.playSpec.add,\n sub: draft.playSpec.sub,\n mul: draft.playSpec.mul,\n div: draft.playSpec.div,\n };\n deriveLevelScores({\n levels: formData.levels,\n highScore: formData.challengeCount,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n });\n\n return formData;\n });\n };\n return (\n getGameFromAbstract(props.gameAbstract) }}\n onSubmit={handleSubmit}\n >\n {(fmFormRenderProps) => {\n return (\n <>\n \n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n setToolbar: (element: JSX.Element) => void;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n const { formData, setFormData } = fmFormRenderProps;\n const [displayTabIndex, setDisplayTabIndex] = useState(0);\n useEffect(() => {\n // Do all derivations in the same place for now\n // If they were to independently update formData, then both updates would be based on the same initial\n // state of formData, and the second change would clobber the first.\n fmFormRenderProps.setDerivedFormData((draftFormData) => {\n deriveLevelScores({\n levels: draftFormData.levels,\n highScore: formData.challengeCount,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n });\n });\n });\n\n useFormToolbar(() => {\n props.setToolbar(\n \n \n \n Edit Compute\n {formData.name}\n \n \n \n \n \n );\n });\n return (\n \n \n
\n \n
\n
\n \n
\n
\n
\n {tabNames[displayTabIndex]}\n
\n\n \n\n \n\n \n\n \n\n \n fmFormRenderProps.setDerivedFormData((draftDerivedFormData) => {\n draftDerivedFormData.isPublished = true;\n })\n }\n />\n
\n );\n};\n","import { makeRequestWithAuthentication } from \"../../../http/authenticated\";\nimport {\n ApiRequest,\n ApiResponseHeader,\n UserGameSettings,\n} from \"../../../domain/serverContract\";\n\nlet promiseCache: Promise;\n\nexport const clearUserGameSettingsCache = () => {\n promiseCache = undefined;\n};\n\nexport const userGameSettings = async () => {\n if (promiseCache) return promiseCache;\n promiseCache = getUserGameSettings()\n .then((response) => {\n const settings = response.userGameSettings ?? {\n extraWords: [],\n hiddenWords: [],\n includeSensitiveWords: false,\n };\n // Make it easier elsewhere\n settings.extraWords = settings.extraWords ?? [];\n settings.hiddenWords = settings.hiddenWords ?? [];\n settings.includeSensitiveWords = settings.includeSensitiveWords ?? false;\n return settings;\n })\n .catch((error) => {\n promiseCache = undefined;\n throw error;\n });\n return promiseCache;\n};\n\nexport interface GetUserGameSettingsRequest extends ApiRequest {}\n\nexport interface GetUserGameSettingsResponse extends ApiResponseHeader {\n userGameSettings: UserGameSettings;\n}\n\nasync function getUserGameSettings(): Promise {\n return makeRequestWithAuthentication({}, \"/api/get_user_game_settings\");\n}\n\nexport interface SaveUserGameSettingsRequest {\n userGameSettings: UserGameSettings;\n}\n\nexport interface SaveUserGameSettingsResponse extends ApiResponseHeader {}\n\n// Saves settings to the database\n// Updates cache if save is successful\nexport async function saveUserGameSettings(\n mutator: (draftUserGameSettings: UserGameSettings) => void\n): Promise {\n const settings = await promiseCache;\n const tempUserGameSettings = Object.assign({}, settings);\n mutator(tempUserGameSettings);\n const response = await makeRequestWithAuthentication<\n SaveUserGameSettingsResponse\n >({ userGameSettings: tempUserGameSettings }, \"/api/save_user_game_settings\");\n mutator(settings);\n return response;\n}\n","import { dictionaryWords } from \"./generated/dictionaryWords\";\nimport { sensitiveWords } from \"./generated/sensitiveWords\";\nimport { userGameSettings } from \"../../requests/manageUserGameSettings\";\n\nlet sensitiveWordsMapCache: Record;\nconst makeSnipDictionary = (\n wordCollections: string[][],\n includeSensitiveWords: boolean\n) => {\n const a = performance.now();\n if (sensitiveWordsMapCache === undefined) {\n sensitiveWordsMapCache = sensitiveWords.reduce((map, word) => {\n map[word] = true;\n return map;\n }, Object.create(null));\n }\n\n const wordCount = wordCollections.reduce((sum, collection) => {\n sum += collection.length;\n return sum;\n }, 0);\n console.log(\n \"Total dictionary size in words: \",\n wordCount - (includeSensitiveWords ? 0 : sensitiveWords.length)\n );\n\n const snipDictionary: Record = Object.create(null);\n for (let j = 0; j < wordCollections.length; j++) {\n const dictionary = wordCollections[j];\n for (let i = 0; i < dictionary.length; i++) {\n const word = dictionaryWords[i];\n if (includeSensitiveWords === false && sensitiveWordsMapCache[word])\n continue;\n const letters = [...(word ?? [])].sort();\n let last = letters[0];\n const snip: string[] = [last];\n for (let j = 1; j < letters.length; j++) {\n const letter = letters[j];\n if (last != letter) {\n snip.push(letter);\n last = letter;\n }\n }\n const snipString = snip.join(\"\");\n if (snipDictionary[snipString] === undefined)\n snipDictionary[snipString] = [];\n snipDictionary[snipString].push(word);\n }\n }\n const b = performance.now();\n console.log(\"makeSnipDictionary\", (b - a) / 1000);\n console.log(\"we have snips:\", Object.values(snipDictionary).length);\n return snipDictionary;\n};\n\nlet extraWordsCache: string[];\nlet includeSensitiveWordsCache: boolean;\nlet snipDictionaryCache: Record;\nconst getCurrentSnipDictionary = async (includeSensitiveWords: boolean) => {\n const settings = await userGameSettings();\n if (\n settings.extraWords !== extraWordsCache ||\n includeSensitiveWords != includeSensitiveWordsCache\n ) {\n extraWordsCache = settings.extraWords;\n const dictionaryList = [dictionaryWords, extraWordsCache];\n snipDictionaryCache = makeSnipDictionary(\n dictionaryList,\n includeSensitiveWords\n );\n includeSensitiveWordsCache = includeSensitiveWords;\n }\n return snipDictionaryCache;\n};\n\nlet hiddenWordsMapCache: Record;\nlet hiddenWordsCache: string[];\nconst getCurrentHiddenWordsMap = async () => {\n const settings = await userGameSettings();\n if (settings.hiddenWords !== hiddenWordsCache) {\n hiddenWordsCache = settings.hiddenWords;\n hiddenWordsMapCache = hiddenWordsCache.reduce((map, word) => {\n map[word] = true;\n return map;\n }, Object.create(null));\n }\n return hiddenWordsMapCache;\n};\n\nexport const getWordsThatDoNotMatchCriteria = (\n words: string[],\n requiredLetters: string,\n optionalLetters: string,\n minimumWordLength: number\n) => {\n // Not converting to lower case.\n // All word inputs and all dictionaries are lower case only, so we should not see upper case letters here.\n const rls = [...(requiredLetters ?? [])];\n const ols = [...(optionalLetters ?? [])];\n const allLetters = [...rls, ...ols];\n return words.reduce((result, word) => {\n if (word.length < minimumWordLength) {\n result.push(word);\n return result;\n }\n if (undefined !== rls.find((rl) => word.indexOf(rl) < 0)) {\n result.push(word);\n return result;\n }\n if (\n undefined !== [...(word ?? [])].find((l) => allLetters.indexOf(l) < 0)\n ) {\n result.push(word);\n return result;\n }\n return result;\n }, []);\n};\n\n// Assumes the word consists only of letters in allLetters\nexport const isPangram = (word: string, allLetters: string[]) => {\n return undefined === allLetters.find((letter) => word.indexOf(letter) < 0);\n};\n\nexport const isWordInDictionary = (word: string) => {\n return dictionaryWords.indexOf(word) < 0 ? false : true;\n};\n\n// z[\"udl\"] = dull, dud\n// # of sets of n letters = 2^n (includes empty set)\n// # sets if n letters where n > 2 = 2^n - 2^2\n// 7 letters => 45\n// 10 letters => 1021\n// For each letter combination that has the required letters:\n// * sort the combination ascending\n// * look up list of matching words\n// * eliminate short words\n//\n// Generate combinations\n// * First generate combinations of optional letters\n// * Loop from 1 to 2^o-1\n// * Make bin map\n// * If fewer than r bits, discard\n// * Take the letters corresponding to the ones\n// * Once done, add in required letters.\n//\n\nconst makeSnips = (optionalLetters: string[], requiredLetters: string[]) => {\n const o = optionalLetters.length;\n const rlCount = requiredLetters.length;\n const b1 = 1;\n const b2 = (2 << (o - 1)) - 1;\n const clips: string[][] = [];\n for (let b = b1; b <= b2; b++) {\n let pattern = 1;\n const included = optionalLetters.reduce((result, letter) => {\n if (pattern & b) result.push(letter);\n pattern = pattern << 1;\n return result;\n }, [] as string[]);\n clips.push(included);\n }\n const snips = clips.map((clip) => {\n if (requiredLetters) clip.push(...requiredLetters);\n return clip.sort().join(\"\");\n });\n if (rlCount > 0) snips.push(requiredLetters.sort().join(\"\"));\n console.log({ snips });\n return snips;\n};\n\nexport const findWords = async (\n requiredLetters: string,\n optionalLetters: string,\n minimumWordLength: number,\n maxWordCount: number\n) => {\n const a = performance.now();\n const settings = await userGameSettings();\n const snips = makeSnips(\n [...(optionalLetters ?? [])],\n [...(requiredLetters ?? [])]\n );\n const snipDictionary = await getCurrentSnipDictionary(\n settings.includeSensitiveWords\n );\n const hiddenWordsMap = await getCurrentHiddenWordsMap();\n const words = snips.reduce((foundWords, snip) => {\n const wordList = snipDictionary[snip];\n if (!wordList) return foundWords;\n const addWords = wordList.filter(\n (word) =>\n word.length >= minimumWordLength &&\n foundWords.length <= maxWordCount &&\n hiddenWordsMap[word] === undefined\n );\n foundWords.push(...addWords);\n return foundWords;\n }, [] as string[]);\n const b = performance.now();\n console.log(\"findWords\", (b - a) / 1000);\n return words;\n};\n","import RadioButtonUncheckedOutlined from \"@material-ui/icons/RadioButtonUncheckedOutlined\";\nimport * as React from \"react\";\nimport Button from \"@material-ui/core/Button\";\n\nexport interface LetterButtonComponentProps {\n letter: string;\n isRequired?: boolean;\n onClick?: (letter: string) => void;\n}\nconst LetterButtonComponentInternal = (props: LetterButtonComponentProps) => {\n const { isRequired, letter, onClick } = props;\n return (\n {\n onClick && onClick(letter);\n }}\n >\n \n
{letter}
\n {isRequired && (\n \n \n \n )}\n \n \n );\n};\n\nexport const LetterButtonComponent = React.memo(\n LetterButtonComponentInternal,\n (prevProps, nextProps) => {\n if (prevProps.isRequired !== nextProps.isRequired) return false;\n if (prevProps.letter !== nextProps.letter) return false;\n if (prevProps.onClick !== nextProps.onClick) return false;\n return true;\n }\n);\n","import Box from \"@material-ui/core/Box\";\nimport * as React from \"react\";\nimport { LetterButtonComponent } from \"./LetterButtonComponent\";\n\nexport interface LettersComponentProps {\n letters: string;\n requiredLetters: string;\n onClick: (letter: string) => void;\n}\nconst LettersComponentInternal = (props: LettersComponentProps) => {\n const { letters, requiredLetters, onClick } = props;\n return (\n <>\n {[...(letters ?? [])].map((letter, index) => {\n return (\n \n requiredLetter === letter\n )\n }\n />\n \n );\n })}\n \n );\n};\n\nexport const LettersComponent = React.memo(\n LettersComponentInternal,\n (prevProps, nextProps) => {\n if (prevProps.letters !== nextProps.letters) return false;\n if (prevProps.requiredLetters !== nextProps.requiredLetters) return false;\n return true;\n }\n);\n","import Box from \"@material-ui/core/Box\";\nimport Grid from \"@material-ui/core/Grid\";\nimport * as React from \"react\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport {\n findDuplicates,\n makeSeparatedStringFromList,\n} from \"../../../../../utilities\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n words: string;\n}\n\nexport interface AddWordsDialogProps {\n submitHandler: (words: string[]) => Promise;\n title: string;\n}\n\nexport let getWordsDialogInternal: Dialog;\n\nexport const openAddWordsDialog = (props: AddWordsDialogProps) => {\n if (!getWordsDialogInternal) {\n getWordsDialogInternal = makeAddWordsDialogComponent();\n }\n return getDialogMethods().open(getWordsDialogInternal, props);\n};\n\nexport const makeAddWordsDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const { submitHandler } = dialogRenderProps.props;\n const fmFormSubmitHandler = (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const words = formData.words.trim().replace(/\\s+/g, \" \").split(\" \");\n if (words.length === 0 || words[0] === \"\") {\n return Promise.reject(\"There are no words to add.\");\n }\n const dups = findDuplicates(words);\n if (dups.length > 0) {\n return Promise.reject(\n \"These words were entered more than once in your list: \" +\n makeSeparatedStringFromList(dups)\n );\n }\n return submitHandler(words);\n };\n\n return (\n \n Promise.resolve({ words: \"\", fmFormDataVersion: undefined }),\n }}\n onSubmit={fmFormSubmitHandler}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: string[]) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={dialogRenderProps.props.title}\n okayText={dialogRenderProps.props.title}\n >\n \n \n Enter one or more words, separated by spaces or new lines.\n \n \n \n \n name=\"words\"\n width=\"100%\"\n textFieldProps={{ multiline: true, rows: 6 }}\n forceToLowerCase\n initialFocus\n />\n \n \n \n )}\n \n );\n },\n });\n};\n","import * as React from \"react\";\nimport { FixedSizeList as List } from \"react-window\";\nimport DeleteIcon from \"@material-ui/icons/HighlightOff\";\nimport { IconButton, makeStyles, Theme, createStyles } from \"@material-ui/core\";\nimport AutoSizer from \"react-virtualized-auto-sizer\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n divider: {\n width: \"100%\",\n marginBottom: \"0.25rem\",\n },\n rulesPrologue: {\n width: \"70%\",\n padding: \"0.5rem\",\n },\n bonus: {\n marginLeft: \"0.5rem\",\n marginRight: \"0.5rem\",\n },\n tabName: {\n marginBottom: \"1rem\",\n },\n info: {\n padding: \"0.5rem\",\n margin: \"0.75rem\",\n },\n });\n});\n\nexport interface VirtualizedWordListProps {\n words: string[];\n removeWord: (words: string) => void;\n}\n\nconst rowRenderer = (args: {\n index: number;\n style: React.CSSProperties;\n words: string[];\n removeWord: (words: string) => void;\n}) => {\n return (\n
\n \n
{args.words[args.index]}
\n args.removeWord(args.words[args.index])}\n >\n \n \n
\n \n );\n};\n\nconst getItemKey = (index: number, data: string[]) => {\n return data[index];\n};\n\nexport const VirtualizedWordList = (props: VirtualizedWordListProps) => {\n const { words } = props;\n const rowFunc = (args: { index: number; style: React.CSSProperties }) =>\n rowRenderer({\n index: args.index,\n style: args.style,\n words,\n removeWord: props.removeWord,\n });\n return (\n \n {({ height, width }) => {\n return (\n \n {rowFunc}\n \n );\n }}\n \n );\n};\n","import { useState, useRef } from \"react\";\n\n// Fresh means:\n// * value not captured by closure\n// * value is gettable syncronously\nexport const useFreshState = (\n f: () => TState\n): [() => TState, (s: TState) => void] => {\n const currentState = useRef(undefined);\n const [_reactState, setReactState] = useState(() => {\n const initialValue = f();\n currentState.current = initialValue;\n return initialValue;\n });\n const setter = (s: TState) => {\n currentState.current = s;\n setReactState(s);\n };\n const getter = () => {\n return currentState.current;\n };\n return [getter, setter];\n};\n","import { IconButton, InputAdornment, TextField } from \"@material-ui/core\";\nimport DeleteIcon from \"@material-ui/icons/HighlightOff\";\nimport * as React from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { useFormToolbar } from \"../../../formManager/useFormToolbar\";\nimport { openAddWordsDialog } from \"../games/spell/components/AddWordsDialog\";\nimport { VirtualizedWordList } from \"../games/spell/components/VirtualizedWordList\";\nimport { isWordInDictionary } from \"../games/spell/wordFinder\";\nimport { useFreshState } from \"../../../hooks/useFreshState\";\nimport {\n saveUserGameSettings,\n userGameSettings,\n} from \"../requests/manageUserGameSettings\";\nimport {\n intersection,\n makeSeparatedStringFromList,\n union,\n} from \"../../../utilities\";\nimport { SecondaryButton, SubtleButton } from \"../../../components/buttons\";\nimport { FormToolbarEditorButtons } from \"./FormToolbarEditorButtons\";\nimport PageIntro from \"../../../components/PageIntro\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { TellMeMore } from \"../../../components/TellMeMore\";\nimport { ToolbarTitle } from \"../../../components/ToolbarTitle\";\nimport { notifySuccess } from \"../../../components/NotificationManager\";\n\nexport const validateWords = (\n words: string[],\n theseWords: string[],\n theseName: string,\n otherWords: string[],\n otherName: string\n) => {\n const alreadyFound = intersection(words, theseWords);\n if (alreadyFound.length > 0) {\n return (\n \"These words are duplicates of words already in your \" +\n theseName +\n \" words list: \" +\n makeSeparatedStringFromList(alreadyFound)\n );\n }\n const hidden = intersection(words, otherWords);\n if (hidden.length > 0) {\n return (\n \"These words are duplicates of words already in your \" +\n otherName +\n \" words list, and therefore would cause them to be ignored: \" +\n makeSeparatedStringFromList(hidden)\n );\n }\n if (theseName == \"extra\") {\n const inDictionary = words.filter((word) => {\n return isWordInDictionary(word);\n });\n if (inDictionary.length > 0) {\n return (\n \"These words are already in the dictionary, and cannot be added to your extra words list: \" +\n makeSeparatedStringFromList(inDictionary)\n );\n }\n }\n};\n\nexport interface FormData {\n fmFormDataVersion: number; // required by FmForm\n extraWords: string[]; // need for validation when adding words\n hiddenWords: string[];\n}\n\nexport interface HiddenWordsPageProps {\n setToolbar: (element: JSX.Element) => void;\n}\nexport const HiddenWordsPage = (props: HiddenWordsPageProps) => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n return saveUserGameSettings((userGameSettings) => {\n userGameSettings.hiddenWords = formData.hiddenWords;\n });\n };\n\n return (\n {\n const settings = await userGameSettings();\n return {\n fmFormDataVersion: undefined,\n extraWords: settings.extraWords,\n hiddenWords: settings.hiddenWords,\n };\n },\n }}\n onSubmit={handleSubmit}\n >\n {(fmFormRenderProps) => {\n return (\n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n setToolbar: (element: JSX.Element) => void;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n const hiddenWords = fmFormRenderProps.formData.hiddenWords;\n const [getFilter, setFilter] = useFreshState(() => \"\");\n const ref = useRef(null);\n useEffect(() => {\n const inputElement: HTMLInputElement = ref.current;\n if (inputElement) inputElement.focus();\n }, []);\n const filteredWords = fmFormRenderProps.formData.hiddenWords\n .filter((word) => word.indexOf(getFilter()) >= 0)\n .sort();\n\n useFormToolbar(() => {\n props.setToolbar(\n \n Settings: Hidden Words\n \n \n );\n });\n\n return (\n \n \n The words in this list will be hidden when finding game words in the\n built-in dictionary. You can manually add hidden words to individual\n games.\n \n The built-in dictionary contains many obscure or technical words that\n may not be appropriate for your audience. When searching, a word is\n found only if that word is\n
    \n
  • \n in the built-in dictionary and is not excluded by virtue of being\n on the built-in sensitive word list\n
  • \n
  • OR is in your extra words list (on this page)
  • \n
  • AND is not in your hidden words list.
  • \n
\n You won't be able to add words that are in your extra words list\n because that would cause those extra words to be ignored. First remove\n them from your extra words list, then add them to your hidden words\n list.\n
\n

\n To share with others:\n {\n navigator.clipboard.writeText(\n makeSeparatedStringFromList(filteredWords)\n );\n notifySuccess(\"Copied\");\n }}\n >\n Copy words to clipboard\n \n

\n
\n \n \n openAddWordsDialog({\n title: \"Add Hidden Words\",\n submitHandler: (words) => {\n const errorMessage = validateWords(\n words,\n [], // don't send hidden words -- prevents rejection for dups\n \"hidden\",\n fmFormRenderProps.formData.extraWords,\n \"extra\"\n );\n if (errorMessage) return Promise.reject(errorMessage);\n fmFormRenderProps.setFormData((draftFormData) => {\n draftFormData.hiddenWords = union(hiddenWords, words);\n draftFormData.hiddenWords.sort((a, b) =>\n a < b ? -1 : a > b ? 1 : 0\n );\n });\n return Promise.resolve();\n },\n })\n }\n >\n Add Words\n \n\n {\n fmFormRenderProps.setFormData((draftFormData) => {\n filteredWords.forEach((filteredWord) => {\n const index = draftFormData.hiddenWords.indexOf(filteredWord);\n draftFormData.hiddenWords.splice(index, 1);\n });\n });\n }}\n >\n Delete {filteredWords.length} Word\n {`${filteredWords.length !== 1 ? \"s\" : \"\"} Below`}\n \n \n \n As you type into the word filter, you will see only matching words. If\n you use the DELETE button it will delete only the matching words.\n \n
\n \n {\n setFilter(\"\");\n }}\n >\n \n \n \n ),\n style: { maxWidth: \"20rem\" },\n }}\n onChange={(event) => {\n const ftext: string = event.currentTarget.value;\n setFilter(ftext);\n }}\n />\n
\n\n
\n {\n // So we also need to update form data -- which is also what dirties the page.\n fmFormRenderProps.setFormData((draftFormData) => {\n const delIndex = draftFormData.hiddenWords.indexOf(word);\n draftFormData.hiddenWords.splice(delIndex, 1);\n });\n }}\n />\n
\n
\n );\n};\n","import Box from \"@material-ui/core/Box\";\nimport Grid from \"@material-ui/core/Grid\";\nimport * as React from \"react\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport {\n findDuplicates,\n intersection,\n makeSeparatedStringFromList,\n} from \"../../../../../utilities\";\nimport { getWordsThatDoNotMatchCriteria } from \"../wordFinder\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n words: string;\n}\n\nexport interface AddGameWordsDialogProps {\n requiredLetters: string;\n optionalLetters: string;\n minimumWordLength: number;\n foundWords: string[];\n}\n\nexport let getWordsDialogInternal: Dialog;\n\nexport const openAddGameWordsDialog = (props: AddGameWordsDialogProps) => {\n if (!getWordsDialogInternal) {\n getWordsDialogInternal = makeAddGameWordsDialogComponent();\n }\n return getDialogMethods().open(getWordsDialogInternal, props);\n};\n\nexport const makeAddGameWordsDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const {\n minimumWordLength,\n optionalLetters,\n requiredLetters,\n foundWords,\n } = dialogRenderProps.props;\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const words = formData.words.trim().replace(/\\s+/g, \" \").split(\" \");\n if (words.length === 0 || words[0] === \"\")\n return Promise.reject(\"There are no words to add.\");\n const mismatched = getWordsThatDoNotMatchCriteria(\n words,\n requiredLetters,\n optionalLetters,\n minimumWordLength\n );\n if (mismatched.length > 0) {\n return Promise.reject(\n \"These words do not meet the game criteria: \" +\n makeSeparatedStringFromList(mismatched)\n );\n }\n const alreadyFound = intersection(foundWords, words);\n if (alreadyFound.length > 0) {\n return Promise.reject(\n \"These words are duplicates of words already found: \" +\n makeSeparatedStringFromList(alreadyFound)\n );\n }\n\n const dups = findDuplicates(words);\n if (dups.length > 0) {\n return Promise.reject(\n \"These words were entered more than once in your list: \" +\n makeSeparatedStringFromList(dups)\n );\n }\n\n return Promise.resolve(words);\n };\n\n return (\n \n Promise.resolve({ words: \"\", fmFormDataVersion: undefined }),\n }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: string[]) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Add Words to Game\"}\n okayText={\"Add Words to Game\"}\n >\n \n \n Words you enter here will be added to this game, even if they\n are on your hidden list.\n \n Enter one or more words, separated by spaces or new lines.\n \n If you search for more words or change the game criteria, then\n you will lose the words you added, unless you press Undo.\n \n \n \n \n name=\"words\"\n width=\"100%\"\n forceToLowerCase\n textFieldProps={{ multiline: true, rows: 6 }}\n initialFocus\n />\n \n \n \n )}\n \n );\n },\n });\n};\n","import Box from \"@material-ui/core/Box\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport MenuItem from \"@material-ui/core/MenuItem\";\nimport Paper from \"@material-ui/core/Paper\";\nimport { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\nimport Typography from \"@material-ui/core/Typography\";\nimport PangramIcon from \"@material-ui/icons/Category\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport AdditionalWordsIcon from \"@material-ui/icons/PostAdd\";\nimport LookupIcon from \"@material-ui/icons/Search\";\nimport SettingsIcon from \"@material-ui/icons/Settings\";\nimport SpecialIcon from \"@material-ui/icons/Stars\";\nimport LongestIcon from \"@material-ui/icons/TextRotationNone\";\nimport HiddenIcon from \"@material-ui/icons/VisibilityOff\";\nimport * as React from \"react\";\nimport { SecondaryButton } from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { validateWords } from \"../../../components/HiddenWordsPage\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport { PopupMenu } from \"../../../../../components/PopupMenu\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport {\n saveUserGameSettings,\n userGameSettings,\n} from \"../../../requests/manageUserGameSettings\";\nimport { max } from \"../../../../../utilities\";\nimport { isPangram } from \"../wordFinder\";\nimport { openAddGameWordsDialog } from \"./AddGameWordsDialog\";\n\nconst useStyles = makeStyles(() =>\n createStyles({\n container: {\n overflowY: \"auto\",\n maxHeight: \"11rem\",\n border: \"1px solid black\",\n //backgroundColor: theme.palette.background.paper,\n },\n tile: {\n margin: \".25rem\",\n minWidth: \"10rem\",\n padding: \".25rem .5rem .25rem .5rem\",\n },\n })\n);\n\nexport const GearIcon = () => (\n \n);\n\nexport enum WordSource {\n System,\n Extra,\n}\n\nexport const Tile = (props: {\n word: string;\n source?: WordSource;\n actions: { remove: () => void; toggleSpecial: () => void };\n isPangram: boolean;\n isLongestWord: boolean;\n isSpecialWord: boolean;\n}) => {\n const {\n word,\n source,\n actions,\n isLongestWord,\n isPangram,\n isSpecialWord,\n } = props;\n const classes = useStyles();\n\n return (\n \n \n {\n return [\n {\n window.open(`https://www.google.com/#q=define+${word}`);\n pmProps.close();\n }}\n >\n \n Lookup Word (Google)\n ,\n {\n actions.remove();\n pmProps.close();\n }}\n >\n \n Remove Word\n ,\n {\n props.actions.toggleSpecial();\n pmProps.close();\n }}\n >\n \n {props.isSpecialWord ? \"Remove Special\" : \"Make Special\"}\n ,\n {\n const settings = await userGameSettings();\n const errorMessage = validateWords(\n [word],\n settings.hiddenWords,\n \"hidden\",\n settings.extraWords,\n \"extra\"\n );\n if (errorMessage) {\n notifyError(errorMessage);\n return;\n }\n saveUserGameSettings((userGameSettings) => {\n userGameSettings.hiddenWords = [\n ...userGameSettings.hiddenWords,\n word,\n ];\n }).then(() => {\n actions.remove();\n pmProps.close();\n });\n }}\n >\n \n Add to Hidden Words (cannot undo) and Remove\n ,\n {\n const settings = await userGameSettings();\n const errorMessage = validateWords(\n [word],\n settings.extraWords,\n \"extra\",\n settings.hiddenWords,\n \"hidden\"\n );\n if (errorMessage) {\n notifyError(errorMessage);\n return;\n }\n saveUserGameSettings((userGameSettings) => {\n userGameSettings.extraWords = [\n ...userGameSettings.extraWords,\n word,\n ];\n }).then(() => {\n pmProps.close();\n });\n }}\n >\n \n Add to Extra Words (cannot undo)\n ,\n ];\n }}\n >\n {() => (\n \n \n \n {word}\n \n \n )}\n \n {source ?? WordSource.System === WordSource.System ? null : (\n \n )}\n \n \n \n \n \n \n \n {\n props.actions.toggleSpecial();\n }}\n >\n \n \n \n \n \n );\n};\n\nexport interface WordListProps {\n items: { word: string; source?: WordSource; isSpecial?: boolean }[];\n actions: {\n addWords: (words: string[]) => void;\n remove: (word: string) => void;\n toggleSpecial: (word: string) => void;\n };\n allLetters: string[];\n requiredLetters: string;\n optionalLetters: string;\n minimumWordLength: number;\n}\nconst WordListInternal = (props: WordListProps) => {\n const greatestLength = max(props.items.map((item) => item.word.length));\n const { items, requiredLetters, optionalLetters, minimumWordLength } = props;\n return (\n \n \n \n {props.items.map((tile) => (\n props.actions.remove(tile.word),\n toggleSpecial: () => props.actions.toggleSpecial(tile.word),\n }}\n isPangram={isPangram(tile.word, props.allLetters)}\n isSpecialWord={tile.isSpecial ?? false}\n isLongestWord={tile.word.length === greatestLength}\n />\n ))}\n \n \n {\n const dr = await openAddGameWordsDialog({\n minimumWordLength,\n optionalLetters,\n requiredLetters,\n foundWords: items.map((item) => item.word),\n });\n if (!dr.isOkay) return;\n const wordsToAddToExtraWordsList = dr.result;\n if (wordsToAddToExtraWordsList?.length > 0) {\n props.actions.addWords(wordsToAddToExtraWordsList);\n }\n }}\n >\n Add Additional Words to This Game\n \n \n );\n};\n\nexport const WordList = React.memo(WordListInternal, (prevProps, nextProps) => {\n if (prevProps.items !== nextProps.items) return false;\n return true;\n});\n","import * as React from \"react\";\nimport { SubtleButton } from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../../components/dialogTools/DialogManager\";\nimport Emphasize from \"../../../../../components/Emphasize\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmForm } from \"../../../../../formManager/FmForm\";\nimport { shuffleString } from \"../../../../../utilities\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n letters: string;\n}\n\nexport interface ReorderLettersDialogProps {\n letters: string;\n}\n\nexport let reorderLettersDialogInternal: Dialog<\n string,\n ReorderLettersDialogProps\n>;\n\nexport const openReorderLettersDialog = (props: ReorderLettersDialogProps) => {\n if (!reorderLettersDialogInternal) {\n reorderLettersDialogInternal = makeReorderLettersDialogComponent();\n }\n return getDialogMethods().open(reorderLettersDialogInternal, props);\n};\n\nexport const makeReorderLettersDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const letters = dialogRenderProps.props.letters;\n return (\n \n suppressPrompt\n name=\"ReorderLettersDialog\"\n suppressSpinner\n fetch={{\n handler: () =>\n Promise.resolve({\n fmFormDataVersion: undefined,\n letters,\n }),\n }}\n onSubmit={(fmProps) => {\n const f = fmProps.formData;\n if (\n f.letters.split(\"\").sort().join(\"\") !==\n letters.split(\"\").sort().join(\"\")\n ) {\n return Promise.reject(\n \"You cannot change the letters here, only the order of the letters.\"\n );\n }\n return Promise.resolve(f.letters);\n }}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: string) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Set Order\"}\n okayText={\"Set Order\"}\n >\n \n \n Reorder the letters ({letters})\n \n \n name=\"letters\"\n labelText=\"Reordered Letters\"\n initialFocus\n width=\"25rem\"\n maxLength={10}\n />\n \n fmProps.setFormData((draft) => {\n draft.letters = shuffleString(draft.letters);\n })\n }\n >\n Shuffle Letters\n \n \n \n )}\n \n );\n },\n });\n};\n","import Box from \"@material-ui/core/Box\";\nimport Divider from \"@material-ui/core/Divider\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport PangramIcon from \"@material-ui/icons/Category\";\nimport SpecialIcon from \"@material-ui/icons/Stars\";\nimport LongestIcon from \"@material-ui/icons/TextRotationNone\";\nimport UndoIcon from \"@material-ui/icons/Undo\";\nimport { Draft } from \"immer\";\nimport * as React from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n SecondaryButton,\n SubtleButton,\n} from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport Hider from \"../../../../../components/Hider\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport SettingsContainer from \"../../../../../components/SettingsContainer\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { FmNumberField, FmTextField } from \"../../../../../formManager/FmField\";\nimport { pickout, shuffle, shuffleString } from \"../../../../../utilities\";\nimport { findWords } from \"../wordFinder\";\nimport { LetterButtonComponent } from \"./LetterButtonComponent\";\nimport { LettersComponent } from \"./LettersComponent\";\nimport { FormData } from \"./SpellEditPage\";\nimport { GearIcon, WordList } from \"./WordList\";\nimport { openReorderLettersDialog } from \"./ReorderLettersDialog\";\n\nconst MAX_WORD_COUNT = 200;\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n divider: {\n width: \"100%\",\n marginBottom: \"0.25rem\",\n },\n });\n});\n\nconst SpellEditPageChooseWordsTabInternal = (props: {\n formData: FormData;\n setFormData: (\n mutator: (formData: Draft) => FormData | void\n ) => FormData;\n isActive: boolean;\n}) => {\n useHelp(\"SpellEditPageChooseWordsTab\", , props.isActive);\n const { formData, setFormData } = props;\n const classes = useStyles();\n const foundWordsLengthRef = useRef(0);\n const [\n showDisappearingLettersHint,\n setShowDisappearingLettersHint,\n ] = useState(false);\n useEffect(() => {\n if (formData.foundWords.length === 0 && foundWordsLengthRef.current > 0) {\n foundWordsLengthRef.current = formData.foundWords.length;\n setShowDisappearingLettersHint(true);\n } else if (formData.foundWords.length > 0) {\n setShowDisappearingLettersHint(false);\n foundWordsLengthRef.current = formData.foundWords.length;\n }\n }, [formData.foundWords.length]);\n\n const wordListWords = useMemo(\n () =>\n formData.foundWords\n .map((word) => {\n return { word: word.word, isSpecial: word.isSpecial };\n })\n .sort((a, b) => (a.word < b.word ? -1 : a.word > b.word ? 1 : 0)),\n [formData.foundWords]\n );\n const wordListAllLetters = useMemo(() => [...(formData.letters ?? [])], [\n formData.letters,\n ]);\n const wordListActions = useMemo(() => {\n return {\n addWords: (words: string[]) => {\n setFormData((draftFormData) => {\n draftFormData.foundWords = [\n ...draftFormData.foundWords,\n ...words.map((word) => {\n return { word, isSpecial: false };\n }),\n ];\n });\n },\n remove: (word: string) => {\n const index = formData.foundWords\n .map((foundWord) => foundWord.word)\n .indexOf(word);\n if (index >= 0) {\n setFormData((draftFormData) => {\n draftFormData.foundWords.splice(index, 1);\n });\n }\n },\n toggleSpecial: (word: string) => {\n const index = formData.foundWords\n .map((foundWord) => foundWord.word)\n .indexOf(word);\n if (index >= 0) {\n setFormData((draftFormData) => {\n draftFormData.foundWords[index].isSpecial = !draftFormData\n .foundWords[index].isSpecial;\n });\n }\n },\n };\n }, [formData.foundWords]);\n\n return (\n \n );\n};\n\nexport const SpellEditPageChooseWordsTab = React.memo(\n SpellEditPageChooseWordsTabInternal,\n (prevProps, nextProps) => {\n if (prevProps.isActive !== nextProps.isActive) return false;\n if (prevProps.formData.foundWords !== nextProps.formData.foundWords)\n return false;\n if (prevProps.formData.letters !== nextProps.formData.letters) return false;\n if (\n prevProps.formData.requiredLetters !== nextProps.formData.requiredLetters\n )\n return false;\n if (\n prevProps.formData.minimumWordLength !==\n nextProps.formData.minimumWordLength\n )\n return false;\n return true;\n }\n);\n\nconst MyHelp = () => {\n return (\n \n Chose Words\n Type Letters to Get Started\n \n Type the letters to be used to form words. Once you type a letter you\n will see more choices.\n \n Choose Required Letters\n \n The letters you type will appear in blue buttons like this{\" \"}\n . Click on a letter to make it\n required. It will then appear in a yellow button, with a circle around\n the letter like this\n . Players must use all of\n the required letters in each correct answer.\n \n\n Search for Words\n \n Press SEARCH FOR WORDS and a suggested list of answers will be\n displayed.\n \n\n Special, Pangram, and Longest Words\n \n Each word in the list of answers may be followed by one or more the the\n following icons, which means they are eligible for extra points based on\n the scoring settings:\n
    \n
  • \n \n Pangram. This word uses all of the letters (possibly more than once)\n
  • \n
  • \n \n Longest. This word is as long or longer than any other answer word.\n
  • \n
  • \n \n Special. You made this word special. Click the gear icon{\" \"}\n to make a word special.\n
  • \n
\n
\n\n Actions on Found Words\n \n Click the gear icon to do one of the following:\n
    \n
  • \n Lookup Word. Opens another tab and runs a Google search on the word.\n
  • \n
  • Remove Word. Removes the word from the list of found words.
  • \n
  • \n Make Special. Marks this word as being special, which gives it extra\n points.\n
  • \n
  • \n Add to Hidden Words (cannot undo) and Remove. Removes the word from\n the list of found words, and prevents it from appearing when you\n search for words -- by adding the word to your hidden words list. If\n you press undo afterward, the word is added back to the list of\n found words, but remains on the hidden words list. If you wish to\n remove it from the hidden words list, you must do so on the Hidden\n Words page.\n
  • \n
  • \n Add to Extra Words (cannot undo). Adds the word to your extra words\n list. If you wish to remove it from the extra words list, you must\n do so on the Hidden Words page. Words in the extra words list appear\n when searching for words.\n
  • \n
\n
\n\n Add Additional Words or Remove Words\n \n Press ADD ADDITIONAL WORDS to add words that didn't appear when you\n pressed SEARCH FOR WORDS. Click the gear icon next to a\n word to remove it from the game, to add it to your list of extra words,\n or to add it to your list of hidden words.\n \n
\n );\n};\n","import MuiDialog from \"@material-ui/core/Dialog\";\nimport DialogActions from \"@material-ui/core/DialogActions\";\nimport DialogContent from \"@material-ui/core/DialogContent\";\nimport DialogTitle from \"@material-ui/core/DialogTitle\";\nimport * as React from \"react\";\nimport { SubtleButton } from \"./buttons\";\nimport {\n getDialogMethods,\n makeDialog,\n Dialog,\n} from \"./dialogTools/DialogManager\";\nimport { useEffect } from \"react\";\n\nexport interface JustOkDialogProps {\n open: boolean;\n onClose: () => void;\n title: string;\n okayText?: string;\n}\nconst keyDownHandler = (event: KeyboardEvent) => {\n // Prevent keys from being handled in the underlying page.\n event.stopPropagation();\n};\n\nexport const JustOkDialog: React.FunctionComponent = (\n props\n) => {\n const { onClose, open, okayText, title } = props;\n const handleClose = () => {\n onClose();\n };\n\n useEffect(() => {\n document.addEventListener(\"keydown\", keyDownHandler, true);\n return () => {\n document.removeEventListener(\"keydown\", keyDownHandler, true);\n };\n });\n\n return (\n \n {title}\n {props.children}\n \n {okayText ?? \"Ok\"}\n \n \n );\n};\n\ninterface InlineJustOkDialogProps {\n title: string;\n okayText?: string;\n content: string | JSX.Element;\n}\n\nlet inlineJustOkDialogInternal: Dialog;\n\nexport const openJustOkDialog = (props: InlineJustOkDialogProps) => {\n if (!inlineJustOkDialogInternal) {\n inlineJustOkDialogInternal = makeJustOkDialog();\n }\n return getDialogMethods().open(inlineJustOkDialogInternal, props);\n};\n\nconst makeJustOkDialog = () => {\n const dialog = makeDialog({\n name: \"JustOkConfirmationDialog\",\n componentRenderer: (props) => {\n return (\n {\n props.close(true, true);\n }}\n open={true}\n title={props.props.title}\n okayText={props.props.okayText}\n >\n {props.props.content}\n \n );\n },\n });\n return dialog;\n};\n","import { Button } from \"@material-ui/core\";\nimport { RadioButtonUncheckedOutlined } from \"@material-ui/icons\";\nimport * as React from \"react\";\n\nexport interface InputButtonComponentProps {\n letter: string;\n isRequired: boolean;\n onClick: () => void;\n}\n\n// InputButtonComponent presents a button in a custom keyboard.\nexport const InputButtonComponent = (props: InputButtonComponentProps) => {\n const { isRequired, letter, onClick } = props;\n\n return (\n {\n onClick();\n }}\n >\n \n
{letter}
\n {isRequired && (\n \n \n \n )}\n \n \n );\n};\n","import { Box, Container } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { SpellPlaySpec } from \"../spell_types\";\nimport { GameInfo } from \"./SpellGameComponent\";\n\nexport interface SpellRulesComponentProps {\n playSpec: SpellPlaySpec;\n gameInfo: GameInfo;\n}\nexport const SpellRulesComponent = (props: SpellRulesComponentProps) => {\n const { playSpec, gameInfo } = props;\n const rulesPrologue = playSpec.rulesPrologue;\n const rulesPrologueComponent = !rulesPrologue ? null : (\n {rulesPrologue}\n );\n return (\n \n {rulesPrologueComponent}\n \n \n The following rules apply to this game:\n
    \n \n
  • \n {`Letters may ${\n gameInfo.canReuseLetters ? \"\" : \"not \"\n } be reused.`}\n
  • \n
  • The shortest word has {gameInfo.minLength} letters.
  • \n
  • \n There{\" \"}\n {gameInfo.pangramCount === 1\n ? \"is one word\"\n : `are ${gameInfo.pangramCount} words`}{\" \"}\n that use{gameInfo.pangramCount === 1 ? \"s\" : \"\"} all of the letters.\n
  • \n
  • \n {`This game has a total of\n ${playSpec.answers.length} possible words worth ${gameInfo.maxPoints} points.\n `}\n {gameInfo.highestLevel.score >= gameInfo.maxPoints\n ? \"\"\n : \" You don't need to find all of the words to achieve the top level.\"}\n
  • \n
\n
\n \n \n The game levels and the number of points needed to reach each level are:{\" \"}\n {props.playSpec.levels.map((level, index) => (\n \n {index > 0 ? \", \" : \"\"}\n {level.name} {level.score}\n \n ))}\n .\n \n \n \n );\n};\n\nexport const makeSeparatedElementStringFromList = (\n list: string[]\n): JSX.Element[] => {\n if (list === undefined) return undefined;\n return list.reduce((result, item, index) => {\n if (index !== 0) result.push(, );\n result.push({item});\n return result;\n }, [] as JSX.Element[]);\n};\n\nconst RequiredLettersInfoComponent = (props: {\n requiredLetters: string;\n}): JSX.Element => {\n const { requiredLetters } = props;\n if (!requiredLetters?.length) return null;\n return (\n
  • \n Each word must include the required letter\n {requiredLetters.length === 1 ? \": \" : \"s: \"}\n {makeSeparatedElementStringFromList(\n [...(requiredLetters ?? [])].map((item) => item.toUpperCase())\n )}\n .\n
  • \n );\n};\n","import * as React from \"react\";\nimport { ConfirmationDialogBase } from \"./dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"./dialogTools/DialogManager\";\n\ninterface InlineConfirmationDialogProps {\n title: string;\n okayText?: string;\n content: string | JSX.Element;\n}\n\nexport const makeInlineConfirmationDialog = () => {\n const dialog = makeDialog({\n name: \"InlineConfirmationDialog\",\n componentRenderer: (props) => {\n return (\n {\n props.close(isOkay, undefined);\n }}\n open={true}\n title={props.props.title}\n okayText={props.props.okayText}\n >\n {props.props.content}\n \n );\n },\n });\n return dialog;\n};\n\nlet inlineConfirmationDialogInternal: Dialog<\n boolean,\n InlineConfirmationDialogProps\n>;\nexport const openConfirmationDialog = (\n props: InlineConfirmationDialogProps\n) => {\n if (!inlineConfirmationDialogInternal) {\n inlineConfirmationDialogInternal = makeInlineConfirmationDialog();\n }\n return getDialogMethods().open(inlineConfirmationDialogInternal, props);\n};\n","import {\n AppBar,\n Button,\n Container,\n IconButton,\n Menu,\n MenuItem,\n Toolbar,\n} from \"@material-ui/core\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport { Menu as MenuIcon, ReplayOutlined } from \"@material-ui/icons\";\nimport * as React from \"react\";\nimport { useClientRect } from \"../../../measure\";\nimport { clearLocalStorageForGame, clearLocalStorage } from \"../localStorage\";\nimport { ToolbarTitle } from \"../../../components/ToolbarTitle\";\nimport { openConfirmationDialog } from \"../../../components/ConfirmationDialog\";\nimport {\n getGameTypeLabel,\n gameTypeHasAnswers,\n gameTypeUsesMenuRestart,\n} from \"../../../domain/types\";\nimport { getGameType } from \"../globalPlayData\";\n\nexport interface TopAppBarProps {\n answers: () => void;\n}\n\nexport const ShareProgressContext = React.createContext(null);\nexport const RulesContext = React.createContext(null);\nexport const RestartContext = React.createContext(null);\n\nlet shareProgressHandler = () => {};\nconst setShareProgressHandler = (handler: () => {}) => {\n shareProgressHandler = handler;\n};\n\nlet rulesHandler = () => {};\nconst setRulesHandler = (handler: () => {}) => {\n rulesHandler = handler;\n};\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n });\n});\n\nexport const TopAppBarComponent: React.FunctionComponent = (\n props\n) => {\n const [rect, ref] = useClientRect();\n const [anchorEl, setAnchorEl] = React.useState(null);\n const classes = useStyles();\n\n const handleMenu = (event: React.MouseEvent) => {\n setAnchorEl(event.currentTarget);\n };\n\n const handleClose = () => {\n setAnchorEl(null);\n };\n const menuOpen = Boolean(anchorEl);\n return (\n <>\n \n \n
    \n \n \n \n
    \n \n {gameTypeUsesMenuRestart(getGameType()) && (\n {\n handleClose();\n const isOkay = await openConfirmationDialog({\n content: (\n \n If you restart the game, all of your answers for this\n game will be deleted from this device. Your shared\n progress will not be deleted. nor will your answers for\n other games.\n \n ),\n title: \"Restart Game\",\n okayText: \"Restart Game\",\n });\n if (isOkay) {\n clearLocalStorageForGame();\n location.reload();\n }\n }}\n >\n Restart\n \n )}\n {\n handleClose();\n const isOkay = await openConfirmationDialog({\n content: (\n \n If you reset the game, all of your answers for all of your\n Cortex games will be deleted from this device. Your shared\n progress will not be deleted. Only use this if you are\n having trouble getting games to work.\n \n ),\n title: \"title\",\n okayText: \"Factory Reset\",\n });\n if (isOkay) {\n clearLocalStorage();\n location.reload();\n }\n }}\n >\n Factory Reset\n \n \n {getGameTypeLabel(getGameType())}\n {gameTypeHasAnswers(getGameType()) && (\n \n )}\n \n \n
    \n
    \n \n \n \n {props.children}\n \n \n \n \n );\n};\n","import { Box, Button, Grid, Typography } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { useContext, useEffect, useReducer, useState } from \"react\";\nimport { openJustOkDialog } from \"../../../components/JustOkDialog\";\nimport {\n notifyErrorTransient,\n notifySuccess,\n notifySuccessTransient,\n} from \"../../../components/NotificationManager\";\nimport { getLevelFromScore, Level } from \"../../../domain/types\";\nimport { shareProgress } from \"../../play/components/ShareProgressComponent\";\n\nimport { storeProgressLocally } from \"../../play/localStorage\";\nimport { SpellPlaySpec, SpellProgress } from \"../spell_types\";\nimport { GuessInputComponent } from \"./GuessInputComponent\";\nimport { LettersComponent } from \"./LettersComponent\";\nimport { ProgressComponent } from \"./ProgressComponent\";\nimport { SpellRulesComponent } from \"./SpellRulesComponent\";\nimport {\n makeSeparatedStringFromList,\n min,\n sum,\n shuffle,\n} from \"../../../utilities\";\nimport {\n ShareProgressContext,\n RulesContext,\n} from \"../../play/components/TopAppBarComponent\";\n\nconst smile = \"\\u{1F600}\";\n\nexport enum DispatchType {\n Add,\n Delete,\n Clear,\n Pop,\n}\n\nexport interface Action {\n type: DispatchType;\n letter?: string;\n}\n\nexport interface AppState {\n pendingAction: Action | undefined;\n}\n\nconst initialAppState: AppState = { pendingAction: undefined };\n\nfunction reducer(_state: AppState, action: Action): AppState {\n switch (action.type) {\n case DispatchType.Add:\n return { pendingAction: action };\n case DispatchType.Delete:\n return { pendingAction: action };\n case DispatchType.Clear:\n return { pendingAction: action };\n case DispatchType.Pop:\n return initialAppState;\n default:\n throw new Error();\n }\n}\n\nexport interface SpellGameComponentProps {\n gameRef: string;\n playSpec: SpellPlaySpec;\n progress: SpellProgress;\n setCurrentProgress: (getProgress: () => SpellProgress) => void;\n}\n\nexport interface GameInfo {\n minLength: number;\n maxPoints: number;\n highestLevel: Level;\n canReuseLetters: boolean;\n pangramCount: number;\n}\n\ninterface InteractiveGameState {\n gameRef: string;\n letters: Array;\n foundWords: string[];\n currentGuess: string;\n}\n\nconst makeStateFromProps = (\n props: SpellGameComponentProps\n): InteractiveGameState => {\n return {\n letters: [\n ...(props.playSpec.requiredLetters ?? []),\n ...(props.playSpec.optionalLetters ?? []),\n ],\n foundWords: props.progress ?? ([] as SpellProgress),\n currentGuess: \"\",\n gameRef: props.gameRef,\n };\n};\n\nexport const getCanReuseLetters = (playSpec: SpellPlaySpec) => {\n return (\n undefined !==\n playSpec.answers.find((answer) => {\n const letters = Array.from(answer.word);\n const letterCount = letters.length;\n // Compare first letter to all following\n // Compare second letter to all following\n // ...stop at next to last letter\n for (let i = 0; i < letterCount - 1; i++) {\n for (let j = i + 1; j < letterCount; j++) {\n if (letters[i] === letters[j]) return true;\n }\n }\n return false;\n })\n );\n};\n\nexport const getPangramCount = (playSpec: SpellPlaySpec) => {\n const answerLetters = [\n ...(playSpec.requiredLetters ?? []),\n ...(playSpec.optionalLetters ?? []),\n ];\n const answerLetterCount = answerLetters.length;\n const pangrams = playSpec.answers.filter((answer) => {\n if (answer.word.length < answerLetterCount) return false; // too short\n for (let i = 0; i < answerLetterCount; i++) {\n if (!answer.word.includes(answerLetters[i])) return false;\n }\n return true;\n });\n return pangrams?.length ?? 0;\n};\n\nexport const getMinLength = (playSpec: SpellPlaySpec) => {\n return min(playSpec.answers.map((answer) => answer.word.length));\n};\n\nexport const SpellGameComponent = (props: SpellGameComponentProps) => {\n const [appState, dispatch] = useReducer(reducer, initialAppState);\n const [gameState, setGameState] = useState(makeStateFromProps(props));\n const [firstTime, setFirstTime] = useState(true);\n props.setCurrentProgress(() => gameState.foundWords);\n const [gameInfo] = useState(\n (): GameInfo => {\n return {\n minLength: getMinLength(props.playSpec),\n maxPoints: sum(props.playSpec.answers.map((answer) => answer.score)),\n highestLevel: props.playSpec.levels[props.playSpec.levels.length - 1],\n pangramCount: getPangramCount(props.playSpec),\n canReuseLetters: getCanReuseLetters(props.playSpec),\n };\n }\n );\n\n const displayRules = () => {\n openJustOkDialog({\n content: (\n \n ),\n title: \"Rules\",\n });\n };\n\n useContext(ShareProgressContext)(() =>\n shareProgress(gameState.gameRef, gameState.foundWords)\n );\n\n useContext(RulesContext)(displayRules);\n\n useEffect(() => {\n // Save state to local storage\n // Only when the correct answers have changed\n // Don't write the first time, because we already either read or wrote the state\n if (firstTime) {\n setFirstTime(false);\n return;\n }\n storeProgressLocally(\n gameState.gameRef,\n (data) => {\n data.progress = gameState.foundWords;\n data.unmodified = false;\n },\n false // means not updated shared progress\n );\n }, [gameState.foundWords]);\n\n const [score, setScore] = useState(0);\n useEffect(() => {\n // Update score when answers change\n const answers = props.playSpec.answers;\n const score = sum(\n gameState.foundWords.map((answerWord) => {\n const found = answers.find((answer) => answer.word === answerWord);\n return found?.score ?? 0;\n })\n );\n setScore(score);\n if (score === 0) displayRules();\n }, [gameState.foundWords]);\n\n const [level, setLevel] = useState(props.playSpec.levels[0]);\n\n const submitHandler = () => {\n if (gameState.currentGuess === \"\") return;\n if (props.playSpec.answers.length === gameState.foundWords.length) {\n notifySuccess(\n `You already found all ${props.playSpec.answers.length} words!`\n );\n return;\n }\n\n if (gameState.foundWords.find((word) => word === gameState.currentGuess)) {\n notifyErrorTransient(`${gameState.currentGuess} was already found`);\n return;\n }\n\n let answer = props.playSpec.answers.find(\n (answer) => answer.word === gameState.currentGuess\n );\n const answerWord = answer?.word;\n const foundWords =\n answerWord === undefined\n ? gameState.foundWords\n : [...gameState.foundWords, answerWord];\n if (answerWord === undefined) {\n if (gameState.currentGuess.length < gameInfo.minLength) {\n notifyErrorTransient(`${gameState.currentGuess} is too short`);\n return;\n }\n if (props.playSpec.requiredLetters?.length > 0) {\n // Find which letters are missing\n const missingLetters = [\n ...(props.playSpec.requiredLetters ?? []),\n ].filter(\n (requiredLetter) =>\n gameState.currentGuess.includes(requiredLetter) === false\n );\n if (missingLetters.length > 0) {\n if (missingLetters.length === 1) {\n notifyErrorTransient(\n `${gameState.currentGuess} is missing one required letter: ${missingLetters[0]}`\n );\n return;\n }\n notifyErrorTransient(\n `${\n gameState.currentGuess\n } is missing these required letters: ${makeSeparatedStringFromList(\n missingLetters\n )}`\n );\n return;\n }\n }\n notifyErrorTransient(\n `${gameState.currentGuess} is not one of the answers`\n );\n return;\n }\n\n const newGameState = {\n ...gameState,\n currentGuess: \"\",\n foundWords,\n };\n setGameState(newGameState);\n dispatch({ type: DispatchType.Clear });\n\n const nextLevel = getLevelFromScore(\n props.playSpec.levels,\n score + answer.score\n );\n const isNewLevel = nextLevel.score !== level.score;\n if (isNewLevel) {\n // openJustOkDialog({content: achievementLevelElement, title: \"Congrats!\"})\n //setShowAchievementLevel(true); //********************************************\n }\n notifySuccessTransient(\n `${answer.word} is worth ${answer.score} points ${smile}`\n );\n setLevel(nextLevel);\n };\n\n const keyUpHandler = (event: KeyboardEvent) => {\n if (event.keyCode === 13) {\n //Enter key\n submitHandler();\n }\n };\n\n useEffect(() => {\n document.addEventListener(\"keyup\", keyUpHandler, false);\n return () => {\n document.removeEventListener(\"keyup\", keyUpHandler, false);\n };\n });\n\n const progressComponent = (\n \n );\n\n return (\n \n \n {props.playSpec.title}\n {props.playSpec.subtitle}\n \n {\n dispatch({ type: DispatchType.Pop });\n }}\n requiredLetters={props.playSpec.requiredLetters}\n optionalLetters={props.playSpec.optionalLetters}\n onChange={(guess: string) => {\n setGameState({\n ...gameState,\n currentGuess: guess,\n });\n }}\n />\n\n \n \n {\n dispatch({ type: DispatchType.Delete });\n }}\n >\n Delete\n \n \n \n \n \n \n {\n dispatch({ type: DispatchType.Add, letter });\n }}\n />\n \n \n {\n const newGameState = {\n ...gameState,\n letters: shuffle(gameState.letters),\n };\n setGameState(newGameState);\n }}\n >\n Shuffle\n \n \n {progressComponent}\n \n );\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport Hider from \"../../../../../components/Hider\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { sum } from \"../../../../../utilities\";\nimport {\n getCanReuseLetters,\n getMinLength,\n getPangramCount,\n} from \"../../../../spell/components/SpellGameComponent\";\nimport { SpellRulesComponent } from \"../../../../spell/components/SpellRulesComponent\";\nimport { SpellPlaySpec } from \"../spellTypes\";\nimport { FormData } from \"./SpellEditPage\";\n\nexport const SpellEditRulesPrologueTab = (props: {\n rulesPrologue: string;\n isActive: boolean;\n playSpec: SpellPlaySpec;\n}) => {\n return (\n \n );\n};\n","import { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport Hider from \"../../../../../components/Hider\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { FmNumberField } from \"../../../../../formManager/FmField\";\nimport { sum } from \"../../../../../utilities\";\nimport { AutoScoringHelp } from \"../../shared/components/AutoScoringHelp\";\nimport { Ladder } from \"../../shared/components/Ladder\";\nimport { FormData } from \"./SpellEditPage\";\n\nconst useStyles = makeStyles(() => {\n return createStyles({\n bonus: {\n marginLeft: \"0.5rem\",\n marginRight: \"0.5rem\",\n },\n });\n});\n\nconst BonusHelp = () => {\n return (\n
      \n
    • \n Pangram bonus: Any word that uses all of the letters is given\n this bonus.\n
    • \n
    • \n Longest word bonus: Any longest word is given this bonus.\n
    • \n
    • \n Special word bonus: Any special word is given this bonus. You\n make a word special by marking it as being special on the Choose Words\n tab.\n
    • \n
    \n );\n};\n\nconst SpellEditScoringTabInternal = (props: {\n formData: FormData;\n isActive: boolean;\n}) => {\n useHelp(\"SpellEditScoringTab\", , props.isActive);\n const { formData } = props;\n const classes = useStyles();\n return (\n \n );\n};\n\nexport const SpellEditScoringTab = React.memo(\n SpellEditScoringTabInternal,\n (prevProps, nextProps) => {\n if (prevProps.isActive !== nextProps.isActive) return false;\n if (prevProps.formData.levels !== nextProps.formData.levels) return false;\n if (prevProps.formData.answers !== nextProps.formData.answers) return false;\n if (prevProps.formData.autoScoring !== nextProps.formData.autoScoring)\n return false;\n if (\n prevProps.formData.autoScoringMethod !==\n nextProps.formData.autoScoringMethod\n )\n return false;\n if (prevProps.formData.pangramBonus !== nextProps.formData.pangramBonus)\n return false;\n if (\n prevProps.formData.longestWordBonus !==\n nextProps.formData.longestWordBonus\n )\n return false;\n if (\n prevProps.formData.specialWordBonus !==\n nextProps.formData.specialWordBonus\n )\n return false;\n return true;\n }\n);\n\nconst MyHelp = () => {\n return (\n <>\n Create Scoring\n \n \n \n );\n};\n","import { Toolbar } from \"@material-ui/core\";\nimport Container from \"@material-ui/core/Container\";\nimport NavigateBefore from \"@material-ui/icons/NavigateBefore\";\nimport NavigateNext from \"@material-ui/icons/NavigateNext\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport {\n MildGuidingButton,\n StrongGuidingButton,\n} from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { FormToolbarEditorButtons } from \"../../../components/FormToolbarEditorButtons\";\nimport Hider from \"../../../../../components/Hider\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport { Title } from \"../../../../../components/Title\";\nimport ToolbarTitle from \"../../../../../components/ToolbarTitle\";\nimport { GameAbstract } from \"../../../../../domain/serverContract\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport { useFormToolbar } from \"../../../../../formManager/useFormToolbar\";\nimport { getGame } from \"../../../requests/getGame\";\nimport { saveGame } from \"../../../requests/saveGame\";\nimport { max, pickout, round, serialId, sum } from \"../../../../../utilities\";\nimport { EditNameGameTab } from \"../../shared/components/EditNameGameTab\";\nimport { EditPublishTab } from \"../../shared/components/EditPublishTab\";\nimport { CommonFormData, FormLevel } from \"../../shared/editorTypes\";\nimport {\n Answer,\n SpellAuthorSpec,\n SpellPlaySpec,\n SpellRecord,\n} from \"../spellTypes\";\nimport { isPangram } from \"../wordFinder\";\nimport { SpellEditPageChooseWordsTab } from \"./SpellEditPageChooseWordsTab\";\nimport { SpellEditRulesPrologueTab } from \"./SpellEditRulesPrologueTab\";\nimport { SpellEditScoringTab } from \"./SpellEditScoringTab\";\nimport { AutoScoringMethod, GameType } from \"../../../../../domain/types\";\nimport {\n clearLevelScoresCache,\n deriveLevelScores,\n} from \"../../shared/deriveLevelScores\";\nimport { FormToolbarPublishButton } from \"../../../components/FormToolbarPublishButton\";\n\nconst GAMETYPE: GameType = \"s\";\n\ninterface FoundWord {\n word: string;\n isSpecial: boolean;\n}\n\nexport interface FormData extends CommonFormData {\n letters: string;\n requiredLetters: string;\n answers: Answer[];\n pangramBonus: number;\n longestWordBonus: number;\n specialWordBonus: number;\n minimumWordLength: number;\n foundWords: FoundWord[];\n}\n\nconst tabNames = [\n \"Name Game\",\n \"Choose Words\",\n \"Create Scoring (optional)\",\n \"Write Rules (optional)\",\n \"Publish\",\n];\n\nconst tabNavNames = [\n \"Name Game\",\n \"Choose Words\",\n \"Create Scoring\",\n \"Write Rules\",\n \"Publish\",\n];\nexport interface SpellEditPageProps {\n setToolbar: (element: JSX.Element) => void;\n gameAbstract: GameAbstract;\n}\n\n// Build gamePlaySpec from formdata\nconst buildPlaySpec = (formData: FormData) => {\n const spellPlaySpec: SpellPlaySpec = {\n answerKey: formData.answerKey,\n answers: formData.answers,\n levels: formData.levels,\n optionalLetters: pickout(formData.requiredLetters, formData.letters),\n requiredLetters: formData.requiredLetters,\n rulesPrologue: formData.rulesPrologue,\n subtitle: formData.subtitle,\n title: formData.title,\n };\n return spellPlaySpec;\n};\n\nexport const SpellEditPage = (props: SpellEditPageProps) => {\n const history = useHistory();\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n if (formData.isPublished && formData.foundWords.length === 0) {\n throw new Error(\"You cannot save a published game with no words.\");\n }\n const spellPlaySpec = buildPlaySpec(formData);\n const spellAuthorSpec: SpellAuthorSpec = {\n longestWordBonus: formData.longestWordBonus,\n specialWordBonus: formData.specialWordBonus,\n pangramBonus: formData.pangramBonus,\n minimumWordLength: formData.minimumWordLength,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n description: formData.description,\n };\n return saveGame({\n id: formData.id,\n gameSpec: { playSpec: spellPlaySpec, authorSpec: spellAuthorSpec },\n name:\n formData.name === fmFormRenderProps.cleanFormData.name\n ? undefined\n : formData.name,\n });\n };\n\n const getGameFromAbstract = async (\n gameAbstract: GameAbstract\n ): Promise => {\n const gameId = gameAbstract.id;\n return getGame({ id: gameId }).then((result) => {\n // blow away memo cache\n memokey_deriveAnswers = undefined;\n clearLevelScoresCache();\n\n const gameRecord = result.gameRecord as SpellRecord;\n const { draft } = gameRecord;\n const name = gameAbstract.name;\n let initialLevels: FormLevel[] = [\n { name: \"Novice\", score: 0, id: serialId() },\n { name: \"Spectacular\", score: 1, id: serialId() },\n ];\n\n const commonFormData: CommonFormData = {\n fmFormDataVersion: 0,\n id: gameId,\n name,\n answerKey: draft.playSpec.answerKey ?? \"\",\n levels:\n draft.playSpec.levels?.map((level) => {\n return {\n name: level.name,\n score: level.score ?? 0,\n id: serialId(),\n };\n }) ?? initialLevels,\n rulesPrologue: draft.playSpec.rulesPrologue ?? \"\",\n subtitle: draft.playSpec.subtitle ?? \"\",\n title: draft.playSpec.title ?? \"\",\n autoScoring: draft.authorSpec.autoScoring ?? true,\n autoScoringMethod:\n draft.authorSpec.autoScoringMethod ?? AutoScoringMethod.Fast,\n description: draft.authorSpec.description ?? \"\",\n isTemplateGame: gameAbstract.template,\n isPublished: !!gameAbstract.published,\n };\n\n const formData: FormData = {\n ...commonFormData,\n requiredLetters: draft.playSpec.requiredLetters ?? \"\",\n letters:\n (draft.playSpec.requiredLetters ?? \"\") +\n (draft.playSpec.optionalLetters ?? \"\"),\n longestWordBonus: draft.authorSpec.longestWordBonus ?? 5,\n pangramBonus: draft.authorSpec.pangramBonus ?? 5,\n specialWordBonus: draft.authorSpec.specialWordBonus ?? 10,\n minimumWordLength: draft.authorSpec.minimumWordLength ?? 4,\n answers: draft.playSpec.answers,\n foundWords:\n draft.playSpec.answers?.map((answer) => {\n return { word: answer.word, isSpecial: answer.isSpecial };\n }) ?? [],\n };\n\n const highScore = formData.answers\n ? sum(formData.answers.map((answer) => answer.score))\n : 0;\n deriveLevelScores({\n levels: formData.levels,\n highScore,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n });\n\n const {\n foundWords,\n letters,\n pangramBonus,\n specialWordBonus,\n longestWordBonus,\n } = formData;\n deriveAnswers(formData, letters, {\n foundWords,\n pangramBonus,\n specialWordBonus,\n longestWordBonus,\n });\n\n return formData;\n });\n };\n return (\n getGameFromAbstract(props.gameAbstract) }}\n onSubmit={handleSubmit}\n >\n {(fmFormRenderProps) => {\n return (\n <>\n \n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n setToolbar: (element: JSX.Element) => void;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n const { formData, setFormData } = fmFormRenderProps;\n const [displayTabIndex, setDisplayTabIndex] = useState(0);\n useEffect(() => {\n // Do all derivations in the same place for now\n // If they were to independently update formData, then both updates would be based on the same initial\n // state of formData, and the second change would clobber the first.\n fmFormRenderProps.setDerivedFormData((draftFormData) => {\n deriveLevelScores({\n levels: draftFormData.levels,\n highScore: formData.answers\n ? sum(formData.answers.map((answer) => answer.score))\n : 0,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n });\n\n const {\n foundWords,\n letters,\n pangramBonus,\n specialWordBonus,\n longestWordBonus,\n } = formData;\n deriveAnswers(draftFormData, letters, {\n foundWords,\n pangramBonus,\n specialWordBonus,\n longestWordBonus,\n });\n });\n });\n\n useFormToolbar(() => {\n props.setToolbar(\n \n \n \n Edit Spell\n {formData.name}\n \n \n \n \n \n );\n });\n return (\n \n \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n {tabNames[displayTabIndex]}\n
    \n\n \n\n \n\n \n\n \n\n \n fmFormRenderProps.setDerivedFormData((draftDerivedFormData) => {\n draftDerivedFormData.isPublished = true;\n })\n }\n gameType={GAMETYPE}\n />\n
    \n );\n};\n\n// Derive functions\n// These functions are used to modify FormData in response to changes in other FormData elements.\n// They should be used when data is loaded to directly set derived data.\n// This keeps the dirty flag from being set at the start.\n// Use \"memoization\" to avoid mutating the state when nothing has changed.\n// In this case, memoization means remembering if we've already mutated the data.\n// Cannot rely in props to useEffect, since useEffect will always run at least once.\n// We clear the memo cache whenever we fetch new data.\n// Otherwise, we might not mutate it with the derived values.\n// 2020-06-26 As of now we don't depended on checking unmutated formData to test for dirty.\n// We user version numbers.\n// So we could allow derived data to mutate after the fetched data is loaded.\n// Leave for now in case we want to revert.\n// The memoization is useful for performance.\n\n// This does the auto scoring\n// It mutates levels, so it can be used to mutate form data inside produce.\n\n// Derive answers\nlet memokey_deriveAnswers: string;\nconst deriveAnswers = (\n formData: FormData, // this is mutated, and is not a dependency\n letters: string, // changing letters clears foundWords, so not needed as a dependency\n dependencies: {\n foundWords: FoundWord[];\n pangramBonus: number;\n specialWordBonus: number;\n longestWordBonus: number;\n }\n) => {\n const memokey = JSON.stringify({\n dependencies,\n });\n if (memokey === memokey_deriveAnswers) return;\n memokey_deriveAnswers = memokey;\n const {\n foundWords,\n longestWordBonus,\n pangramBonus,\n specialWordBonus,\n } = dependencies;\n const greatestLength = max(foundWords.map((item) => item.word.length));\n const allLetters = [...([...(letters ?? [])] ?? [])];\n formData.answers = foundWords.map((foundWord) => {\n const { word, isSpecial } = foundWord;\n let s = word.length;\n s += isPangram(word, allLetters) ? pangramBonus : 0;\n s += isSpecial ? specialWordBonus : 0;\n s += word.length === greatestLength ? longestWordBonus : 0;\n return { word: foundWord.word, score: s, isSpecial };\n });\n};\n","import { Box, Container } from \"@material-ui/core\";\nimport * as React from \"react\";\nimport { TwistPlaySpec } from \"../../../domain/twist_types\";\nimport { pluralize } from \"../../../utilities\";\nimport { GameInfo } from \"./TwistGameComponent\";\n\nexport interface TwistRulesComponentProps {\n playSpec: TwistPlaySpec;\n gameInfo: GameInfo;\n}\nexport const TwistRulesComponent = (props: TwistRulesComponentProps) => {\n const { playSpec, gameInfo } = props;\n const rulesPrologue = playSpec.rulesPrologue;\n const rulesPrologueComponent = !rulesPrologue ? null : (\n {rulesPrologue}\n );\n const challengeCount = playSpec.challenges?.length ?? 0;\n const extraLetterChallengeCount = playSpec.challenges.filter(\n (challenge) =>\n challenge.fillin.length >\n challenge.fixed.split(\"\").filter((letter) => letter === \"*\").length\n ).length;\n return (\n \n {rulesPrologueComponent}\n \n \n

    The following rules apply to this game:

    \n
      \n
    • \n Fill in the missing letters in the top row, using the letters in the\n bottom row.\n
    • \n
    • \n The solutions are{playSpec.caseSensitive ? \" \" : \" not \"}\n case-sensitive.\n
    • \n
    • \n {`The game has ${pluralize(\n challengeCount,\n \"challenge\"\n )} worth a total of ${pluralize(challengeCount, \"point\")}.`}\n {gameInfo.highestLevel.score >= gameInfo.maxPoints\n ? \"\"\n : \" You don't need to solve all of the challenges to achieve the top level.\"}\n
    • \n
    • \n Click a letter in the bottom row to use that letter in the top row.\n Each letter in the bottom row can be used no more than once.\n
    • \n {extraLetterChallengeCount === challengeCount && (\n
    • \n All challenges have extra letters, meaning some letters are not\n used in the solution.\n
    • \n )}\n {extraLetterChallengeCount > 0 &&\n extraLetterChallengeCount < challengeCount && (\n
    • \n {pluralize(extraLetterChallengeCount, \"challenge \")}\n {extraLetterChallengeCount === 1 ? \"has\" : \"have\"} extra\n letters, meaning some letters are not used in the solution.\n
    • \n )}\n
    • The game is over after you have solved all of the challenges.
    • \n
    \n
    \n \n \n The game levels and the number of points needed to reach each level are:{\" \"}\n {props.playSpec.levels.map((level, index) => (\n \n {index > 0 ? \", \" : \"\"}\n {level.name} {level.score}\n \n ))}\n .\n \n \n \n );\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FormData } from \"./TwistEditPage\";\nimport Hider from \"../../../../../components/Hider\";\nimport { TwistRulesComponent } from \"../../../../twist/components/TwistRulesComponent\";\nimport { TwistPlaySpec } from \"../../../../../domain/twist_types\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\n\nexport const TwistEditRulesPrologueTab = (props: {\n rulesPrologue: string;\n isActive: boolean;\n playSpec: TwistPlaySpec;\n}) => {\n return (\n \n );\n};\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport Hider from \"../../../../../components/Hider\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport { Tip } from \"../../../../../components/Tip\";\nimport { AutoScoringHelp } from \"../../shared/components/AutoScoringHelp\";\nimport { Ladder } from \"../../shared/components/Ladder\";\nimport { FormData } from \"./TwistEditPage\";\n\nconst TwistEditScoringTabInternal = (props: {\n formData: FormData;\n isActive: boolean;\n}) => {\n useHelp(\"TwistEditScoringTab\", , props.isActive);\n const { formData } = props;\n return (\n \n );\n};\n\nexport const TwistEditScoringTab = React.memo(\n TwistEditScoringTabInternal,\n (prevProps, nextProps) => {\n if (prevProps.isActive !== nextProps.isActive) return false;\n if (prevProps.formData.levels !== nextProps.formData.levels) return false;\n if (prevProps.formData.autoScoring !== nextProps.formData.autoScoring)\n return false;\n if (\n prevProps.formData.autoScoringMethod !==\n nextProps.formData.autoScoringMethod\n )\n return false;\n return true;\n }\n);\n\nconst MyHelp = () => {\n return (\n <>\n Create Scoring\n \n \n );\n};\n","import * as React from \"react\";\nimport { SubtleButton } from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { Challenge } from \"../../../../../domain/twist_types\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmForm } from \"../../../../../formManager/FmForm\";\nimport { isAnagramOf, shuffleString } from \"../../../../../utilities\";\nimport { TellMeMore } from \"../../../../../components/TellMeMore\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n solution: string;\n fixed: string;\n fillin: string;\n clue: string;\n}\n\nexport interface EditChallengeDialogProps {\n challenge: Challenge;\n // Need solutions to ensure no duplicate solution.\n solutions: string[];\n}\n\nexport let editChallengeDialogInternal: Dialog<\n Challenge,\n EditChallengeDialogProps\n>;\n\nexport const openEditChallengeDialog = (props: EditChallengeDialogProps) => {\n if (!editChallengeDialogInternal) {\n editChallengeDialogInternal = makeEditChallengeDialogComponent();\n }\n return getDialogMethods().open(editChallengeDialogInternal, props);\n};\n\nexport const makeEditChallengeDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const challenge = dialogRenderProps.props.challenge;\n const otherSolutions = dialogRenderProps.props.solutions.filter(\n (solution) => solution !== challenge.solution\n );\n return (\n \n suppressPrompt\n name=\"EditChallengeDialog\"\n suppressSpinner\n fetch={{\n handler: () =>\n Promise.resolve({\n fmFormDataVersion: undefined,\n solution: challenge.solution,\n fixed: challenge.fixed,\n fillin: challenge.fillin,\n clue: challenge.clue,\n }),\n }}\n onSubmit={(fmProps) => {\n const f = fmProps.formData;\n if (f.solution.length !== f.fixed.length) {\n return Promise.reject(\n `The pre-filled letters must have exactly the same number of letters and asterisks (${f.solution.length}) as the solution.`\n );\n }\n const misMatch = f.solution\n .split(\"\")\n .find((sl, i) => sl !== f.fixed[i] && \"*\" != f.fixed[i]);\n if (misMatch !== undefined) {\n return Promise.reject(\n `The pre-filled letters must match the letters on the solution in the same positions.`\n );\n }\n const asterisks = f.fixed.split(\"\").filter((c) => c === \"*\");\n if (asterisks.length > f.fillin.length) {\n return Promise.reject(\n `The number of spaces (asterisks) for pre-filled letters (${asterisks.length}) must be less than or equal to the number of fill-in letters (${f.fillin.length}).`\n );\n }\n if (otherSolutions.includes(f.solution)) {\n return Promise.reject(\"Another challenge has the same solution.\");\n }\n const c: Challenge = {\n solution: f.solution,\n fixed: f.fixed,\n fillin: f.fillin,\n clue: f.clue,\n };\n return Promise.resolve(c);\n }}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: Challenge) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Modify Challenge\"}\n okayText={\"Modify Challenge\"}\n >\n \n Enter the solution.\n \n name=\"solution\"\n labelText={`Solution (${fmProps.formData.solution.length} of 100 max)`}\n placeholderText=\"Solution\"\n initialFocus\n width=\"25rem\"\n maxLength={100}\n onChange={(args) => {\n // Set up other fields if the fixed field is \"virgin\".\n // In that case we shuffle the solution automatically.\n if (\n args.draftFormData.fixed ===\n makeDefaultFixedString(args.oldFieldData)\n ) {\n args.draftFormData.fixed = makeDefaultFixedString(\n args.fieldData\n );\n args.draftFormData.fillin = shuffleString(\n getMinimalFillin(\n args.fieldData,\n args.draftFormData.fixed\n )\n );\n }\n }}\n />\n \n Pre-fill the answer with letters from the solution and\n asterisks. The player will fill-in the spaces occupied by\n asterisks with the fill-in letters. Use all asterisks to\n challenge the player with an anagram. Use the space bar to\n copy a letter from the solution.\n \n \n name=\"fixed\"\n labelText={`Pre-filled letters (${fmProps.formData.fixed.length} of ${fmProps.formData.solution.length})`}\n placeholderText={\"Pre-filled letters\"}\n width=\"25rem\"\n maxLength={fmProps.formData.solution.length}\n onChange={(args) => {\n // Replace spaces with the corresponding letter from the solution.\n let t: string[] = [];\n const c = args.fieldData.split(\"\");\n const s = args.draftFormData.solution.split(\"\");\n for (let i = 0; i < c.length; i++) {\n t[i] = c[i] === \" \" ? s[i] : c[i];\n }\n args.draftFormData.fixed = t.join(\"\");\n }}\n />\n \n The player will replace each asterisk in the the pre-filled\n letters with one of the fill-in letters. There may be more\n fill-in letters than asterisks, but there cannot be fewer.\n \n \n name=\"fillin\"\n placeholderText=\"Fill-in letters\"\n labelText={`Fill-in Letters (${fmProps.formData.fillin.length})`}\n width=\"25rem\"\n maxLength={20}\n />\n \n fmProps.setFormData((draft) => {\n draft.fillin = shuffleString(draft.fillin);\n })\n }\n >\n Shuffle Fill-in Letters\n \n \n \n fmProps.setFormData((draft) => {\n draft.fillin = shuffleString(\n getMinimalFillin(draft.solution, draft.fixed)\n );\n })\n }\n >\n Remove Extra Fill-in Letters\n \n \n This is useful when you add pre-filled letters and wish to\n remove them from the fill-in letters. It takes the letters\n in the solution, removes the pre-filled letters, and then\n shuffles the remaining letters.\n \n \n \n name=\"clue\"\n placeholderText=\"Clue\"\n labelText={`Clue (${fmProps.formData.clue.length} of 250 max)`}\n width=\"25rem\"\n maxLength={250}\n />\n \n \n )}\n \n );\n },\n });\n};\n\n// The default fixed string is spaces for spaces, and asterisks for all other letters.\nexport const makeDefaultFixedString = (t: string) => {\n return t\n .split(\"\")\n .reduce((result, letter) => {\n result.push(letter === \" \" ? \" \" : \"*\");\n return result;\n }, [] as string[])\n .join(\"\");\n};\n\nexport const getMinimalFillin = (solution: string, fixed: string) => {\n return fixed\n .split(\"\")\n .reduce((fillin, fixedLetter) => {\n if (fixedLetter === \"*\") return fillin;\n const index = fillin.findIndex(\n (fillinLetter) => fillinLetter === fixedLetter\n );\n if (index >= 0) {\n fillin.splice(index, 1);\n }\n return fillin;\n }, solution.split(\"\"))\n .join(\"\");\n};\n","import Grow from \"@material-ui/core/Grow\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\nimport AddIcon from \"@material-ui/icons/AddCircle\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport EditIcon from \"@material-ui/icons/Edit\";\nimport * as React from \"react\";\nimport { useRef } from \"react\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport { Challenge } from \"../../../../../domain/twist_types\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmList, FmListRenderProps } from \"../../../../../formManager/FmList\";\nimport { serialId } from \"../../../../../utilities\";\nimport { openEditChallengeDialog } from \"./EditChallengeDialog\";\nimport { FormData } from \"./TwistEditPage\";\n\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n tile: {\n border: \"solid\",\n marginBottom: \"0.25rem\",\n paddingLeft: \"0.5rem\",\n paddingRight: \"0.5rem\",\n },\n tileField: { margin: \"0.25rem 10px 0.25rem 10px\" },\n });\n});\n\nexport interface FormChallenge extends Challenge {\n id: number;\n}\n\nexport interface ChallengeTableProps {\n challenges: Challenge[];\n}\nlet i = 0;\nconst ChallengeTableInternal = (props: ChallengeTableProps) => {\n const highestRenderedIdRef = useRef(-1);\n return (\n \n name=\"challenges\"\n reorder={(\n draftFormData: FormData,\n originalIndex: number,\n newIndex: number\n ) => {\n const moving = draftFormData.challenges[originalIndex];\n draftFormData.challenges = [\n ...draftFormData.challenges.slice(0, originalIndex),\n ...draftFormData.challenges.slice(originalIndex + 1),\n ];\n draftFormData.challenges = [\n ...draftFormData.challenges.slice(0, newIndex),\n moving,\n ...draftFormData.challenges.slice(newIndex),\n ];\n }}\n showAddButton\n addButtonLabel=\"Add Challenge\"\n minItems={0}\n itemAction={async (itemActionRenderProps) => {\n // add is the only action\n const { item, items, position, setFormData } = itemActionRenderProps;\n const r = await openEditChallengeDialog({\n challenge: { solution: \"\", fixed: \"\", fillin: \"\", clue: \"\" },\n solutions: props.challenges.map((c) => c.solution),\n });\n if (!r.isOkay) return;\n const c = r.result;\n const challenge: FormChallenge = {\n solution: c.solution,\n clue: c.clue,\n fixed: c.fixed,\n fillin: c.fillin,\n id: serialId(),\n };\n setFormData((draftFormData) => {\n draftFormData.challenges = [\n ...draftFormData.challenges.slice(0, position + 1),\n challenge,\n ...draftFormData.challenges.slice(position + 1),\n ];\n });\n }}\n >\n {(fmListRenderProps: FmListRenderProps) => {\n const highestRenderedId = highestRenderedIdRef.current;\n if (fmListRenderProps.value.id > highestRenderedId)\n highestRenderedIdRef.current = fmListRenderProps.value.id;\n return (\n c.solution)}\n setValue={fmListRenderProps.setFormDataValue}\n remove={fmListRenderProps.removeItem}\n addBelow={() => fmListRenderProps.itemAction(\"add\")}\n highestRenderedId={highestRenderedId}\n />\n );\n }}\n \n );\n};\n\nexport const TwistChallengeTable = React.memo(\n ChallengeTableInternal,\n (prevProps, nextProps) => {\n if (prevProps.challenges !== nextProps.challenges) return false;\n return true;\n }\n);\n\ninterface ChallengeTileProps {\n challenge: FormChallenge;\n setValue: (challenge: FormChallenge) => void;\n remove: () => void;\n addBelow: () => void;\n highestRenderedId: number;\n solutions: string[];\n}\nconst ChallengeTile = (props: ChallengeTileProps) => {\n const {\n challenge,\n setValue,\n remove,\n addBelow,\n highestRenderedId,\n solutions,\n } = props;\n const classes = useStyles();\n const animate = challenge.id > highestRenderedId;\n return (\n \n \n {\n const r = await openEditChallengeDialog({ challenge, solutions });\n if (r.isOkay) {\n setValue({ ...r.result, id: challenge.id });\n }\n }}\n >\n \n \n \n className={classes.tileField}\n readOnly\n valueProxyFuncs={{\n get: () => challenge.solution,\n mutate: (value) => {},\n }}\n labelText=\"Solution\"\n />\n\n \n className={classes.tileField}\n readOnly\n valueProxyFuncs={{\n get: () => challenge.fixed,\n mutate: (value) => {},\n }}\n labelText=\"Pre-filled Letters\"\n />\n \n className={classes.tileField}\n readOnly\n valueProxyFuncs={{\n get: () => challenge.fillin,\n mutate: (value) => {},\n }}\n labelText=\"Fill-in Letters\"\n />\n \n valueProxyFuncs={{\n get: () => challenge.clue,\n mutate: (value) => {\n setValue({\n clue: value,\n fillin: challenge.fillin,\n fixed: challenge.fixed,\n id: challenge.id,\n solution: challenge.solution,\n });\n },\n }}\n labelText=\"Clue\"\n maxLength={250}\n />\n\n \n addBelow()}\n >\n \n \n \n \n {\n remove();\n }}\n >\n \n \n \n \n \n );\n};\n","import Box from \"@material-ui/core/Box\";\nimport Grid from \"@material-ui/core/Grid\";\nimport * as React from \"react\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { FmTextField } from \"../../../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport {\n findDuplicates,\n makeSeparatedStringFromList,\n intersection,\n} from \"../../../../../utilities\";\nimport { Challenge } from \"../../../../../domain/twist_types\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n words: string;\n}\n\nexport interface BulkAddChallengesDialogProps {\n title: string;\n currentChallenges: Challenge[];\n}\n\nexport interface BulkExport {\n word: string;\n clue: string;\n}\n\nexport let getBulkAddChallengesDialogInternal: Dialog<\n BulkExport[],\n BulkAddChallengesDialogProps\n>;\n\nexport const openBulkAddChallengesDialog = (\n props: BulkAddChallengesDialogProps\n) => {\n if (!getBulkAddChallengesDialogInternal) {\n getBulkAddChallengesDialogInternal = makeBulkAddChallengesDialogComponent();\n }\n return getDialogMethods().open(getBulkAddChallengesDialogInternal, props);\n};\n\nexport const makeBulkAddChallengesDialogComponent = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const { currentChallenges } = dialogRenderProps.props;\n const fmFormSubmitHandler = (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const lines = formData.words\n .replace(/[ \\f\\r\\t\\v]+/g, \" \")\n .trim()\n .split(\"\\n\");\n if (lines.length === 0 || lines[0] === \"\") {\n return Promise.reject(\"There are no words to add.\");\n }\n const bulkExports = lines.map((line) => {\n // Anything after the first comma is the clue.\n const tokens = line.split(\",\", 2);\n return {\n word: tokens[0],\n clue: tokens.length === 1 ? \"\" : tokens[1],\n };\n });\n const words = bulkExports.map((be) => be.word);\n const dups = findDuplicates(words);\n if (dups.length > 0) {\n return Promise.reject(\n \"These words were entered more than once in your list: \" +\n makeSeparatedStringFromList(dups)\n );\n }\n const existing = intersection(\n words,\n currentChallenges.map((challenge) => challenge.solution)\n );\n if (existing.length > 0) {\n return Promise.reject(\n \"These words are already part of existing challenges: \" +\n makeSeparatedStringFromList(dups)\n );\n }\n return Promise.resolve(bulkExports);\n };\n\n return (\n \n Promise.resolve({ words: \"\", fmFormDataVersion: undefined }),\n }}\n onSubmit={fmFormSubmitHandler}\n >\n {(fmProps) => (\n {\n if (isOkay) {\n fmProps\n .submit()\n .then((response: BulkExport[]) => {\n dialogRenderProps.close(true, response);\n return response;\n })\n .catch((reason) => notifyError(reason));\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={dialogRenderProps.props.title}\n okayText={dialogRenderProps.props.title}\n >\n \n \n Enter one or more solutions, one to a line. One challenge will\n be created for each solution. You may also add a comma to a\n line, followed by a clue.\n \n \n \n \n name=\"words\"\n width=\"100%\"\n textFieldProps={{ multiline: true, rows: 6 }}\n initialFocus\n />\n \n \n \n )}\n \n );\n },\n });\n};\n","import EditIcon from \"@material-ui/icons/Edit\";\nimport { Draft } from \"immer\";\nimport * as React from \"react\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport Emphasize from \"../../../../../components/Emphasize\";\nimport { useHelp } from \"../../../../../components/HelpDialog\";\nimport Hider from \"../../../../../components/Hider\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport SettingHeader from \"../../../../../components/SettingHeader\";\nimport SettingsContainer from \"../../../../../components/SettingsContainer\";\nimport SettingSubheader from \"../../../../../components/SettingSubheader\";\nimport { FmSwitchField } from \"../../../../../formManager/FmField\";\nimport { TwistChallengeTable } from \"./TwistChallengeTable\";\nimport { FormData } from \"./TwistEditPage\";\nimport { PrimaryButton } from \"../../../../../components/buttons\";\nimport { openBulkAddChallengesDialog } from \"./BulkAddChallengesDialog\";\nimport { Challenge } from \"../../../../../domain/twist_types\";\nimport { shuffleString } from \"../../../../../utilities\";\nimport {\n makeDefaultFixedString,\n getMinimalFillin,\n} from \"./EditChallengeDialog\";\n\nconst TwistEditChallengesTabInternal = (props: {\n formData: FormData;\n setFormData: (\n mutator: (formData: Draft) => FormData | void\n ) => FormData;\n isActive: boolean;\n}) => {\n useHelp(\"TwistEditChallengesTab\", , props.isActive);\n const { formData, setFormData } = props;\n return (\n \n );\n};\n\nexport const TwistEditChallengesTab = React.memo(\n TwistEditChallengesTabInternal,\n () => {\n return false;\n }\n);\n\nconst MyHelp = () => {\n return (\n \n Chose Challenges\n Case Sensitive\n \n If enabled, then answers must be the same case as the solutions. If\n disabled, then case doesn't matter.\n \n\n Challenges\n \n Add a challenge by pressing the ADD CHALLENGE button. The Modify\n Challenge dialog will open. See below for help with the Modify Challenge\n dialog.\n \n \n Challenges will be presented in the order displayed on the Choose\n Challenges page. Reorder the challenges by dragging them into new\n positions.\n \n\n Modifying a Challenge\n \n To modify a challenge, click the edit icon: . The Modify\n Challenge dialog will open. In the dialog, you can enter or modify the\n following:\n
      \n
    • \n Solution: The solution is the solution to the\n challenge.\n
    • \n
    • \n Pre-filled letters: To make a challenge\n easier, pre-fill some of the letters. Type an asterisk (*) to\n represent a \"blank\" position which the player must fill. Type a\n letter in the solution to cause that letter to be pre-filled in the\n answer. Type a space as a short-cut to typing a letter in the\n solution.\n
    • \n
    • \n Fill-in Letters: The fill-in letters are the\n letters the play must choose from to solve the challenge. You can\n provide extra letters, unused in the solution, to make the challenge\n more difficult.\n
    • \n
    • \n Clue: The clue is presented along with the\n challenge. It is optional.\n
    • \n
    \n
    \n
    \n );\n};\n","import { Toolbar } from \"@material-ui/core\";\nimport Container from \"@material-ui/core/Container\";\nimport NavigateBefore from \"@material-ui/icons/NavigateBefore\";\nimport NavigateNext from \"@material-ui/icons/NavigateNext\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport {\n MildGuidingButton,\n StrongGuidingButton,\n} from \"../../../../../components/buttons\";\nimport { ColumnContainer } from \"../../../../../components/ColumnContainer\";\nimport { FormToolbarEditorButtons } from \"../../../components/FormToolbarEditorButtons\";\nimport Hider from \"../../../../../components/Hider\";\nimport { RowContainer } from \"../../../../../components/RowContainer\";\nimport { Title } from \"../../../../../components/Title\";\nimport ToolbarTitle from \"../../../../../components/ToolbarTitle\";\nimport { GameAbstract } from \"../../../../../domain/serverContract\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport { useFormToolbar } from \"../../../../../formManager/useFormToolbar\";\nimport { getGame } from \"../../../requests/getGame\";\nimport { saveGame } from \"../../../requests/saveGame\";\nimport { round, serialId } from \"../../../../../utilities\";\nimport { EditNameGameTab } from \"../../shared/components/EditNameGameTab\";\nimport { EditPublishTab } from \"../../shared/components/EditPublishTab\";\nimport { CommonFormData, FormLevel } from \"../../shared/editorTypes\";\n\nimport { TwistEditRulesPrologueTab } from \"./TwistEditRulesPrologueTab\";\nimport { TwistEditScoringTab } from \"./TwistEditScoringTab\";\nimport { TwistEditChallengesTab } from \"./TwistEditChallengesTab\";\nimport {\n PlaySpec,\n AutoScoringMethod,\n GameType,\n} from \"../../../../../domain/types\";\nimport {\n TwistRecord,\n TwistAuthorSpec,\n TwistPlaySpec,\n Challenge,\n} from \"../../../../../domain/twist_types\";\nimport {\n clearLevelScoresCache,\n deriveLevelScores,\n} from \"../../shared/deriveLevelScores\";\nimport { FormToolbarPublishButton } from \"../../../components/FormToolbarPublishButton\";\nconst GAMETYPE: GameType = \"t\";\nexport interface FormData extends CommonFormData {\n // ChallengeCount is the number of challenges in a game.\n challenges: Challenge[];\n caseSensitive: boolean;\n}\n\nconst tabNames = [\n \"Name Game\",\n \"Choose Challenges\",\n \"Create Scoring (optional)\",\n \"Write Rules (optional)\",\n \"Publish\",\n];\n\nconst tabNavNames = [\n \"Name Game\",\n \"Choose Challenges\",\n \"Create Scoring\",\n \"Write Rules\",\n \"Publish\",\n];\n\n// Build gamePlaySpec from formdata\nconst buildPlaySpec = (formData: FormData) => {\n const playSpec: PlaySpec = {\n answerKey: formData.answerKey,\n levels: formData.levels,\n subtitle: formData.subtitle,\n title: formData.title,\n rulesPrologue: formData.rulesPrologue,\n };\n const twistPlaySpec: TwistPlaySpec = {\n ...playSpec,\n challenges: formData.challenges,\n caseSensitive: formData.caseSensitive,\n };\n return twistPlaySpec;\n};\n\nexport interface TwistEditPageProps {\n setToolbar: (element: JSX.Element) => void;\n gameAbstract: GameAbstract;\n}\nexport const TwistEditPage = (props: TwistEditPageProps) => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const twistPlaySpec = buildPlaySpec(formData);\n const authorSpec: TwistAuthorSpec = {\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n description: formData.description,\n };\n return saveGame({\n id: formData.id,\n gameSpec: { playSpec: twistPlaySpec, authorSpec },\n name:\n formData.name === fmFormRenderProps.cleanFormData.name\n ? undefined\n : formData.name,\n });\n };\n\n const getGameFromAbstract = async (\n gameAbstract: GameAbstract\n ): Promise => {\n const gameId = gameAbstract.id;\n return getGame({ id: gameId }).then((result) => {\n // blow away memo cache\n clearLevelScoresCache();\n\n const gameRecord = result.gameRecord as TwistRecord;\n const { draft } = gameRecord;\n const name = gameAbstract.name;\n let initialLevels: FormLevel[] = [\n { name: \"Novice\", score: 0, id: serialId() },\n { name: \"Spectacular\", score: 1, id: serialId() },\n ];\n\n const commonFormData: CommonFormData = {\n fmFormDataVersion: 0,\n id: gameId,\n name,\n answerKey: draft.playSpec.answerKey ?? \"\",\n levels:\n draft.playSpec.levels?.map((level) => {\n return {\n name: level.name,\n score: level.score ?? 0,\n id: serialId(),\n };\n }) ?? initialLevels,\n rulesPrologue: draft.playSpec.rulesPrologue ?? \"\",\n subtitle: draft.playSpec.subtitle ?? \"\",\n title: draft.playSpec.title ?? \"\",\n description: draft.authorSpec.description ?? \"\",\n autoScoring: draft.authorSpec.autoScoring ?? true,\n autoScoringMethod:\n draft.authorSpec.autoScoringMethod ?? AutoScoringMethod.Fast,\n isTemplateGame: gameAbstract.template,\n isPublished: !!gameAbstract.published,\n };\n const formData: FormData = {\n ...commonFormData,\n challenges: draft.playSpec.challenges ?? [],\n caseSensitive: draft.playSpec.caseSensitive,\n };\n deriveLevelScores({\n levels: formData.levels,\n highScore: formData.challenges?.length,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n });\n\n return formData;\n });\n };\n return (\n getGameFromAbstract(props.gameAbstract) }}\n onSubmit={handleSubmit}\n >\n {(fmFormRenderProps) => {\n return (\n <>\n \n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n setToolbar: (element: JSX.Element) => void;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n const { formData, setFormData } = fmFormRenderProps;\n const [displayTabIndex, setDisplayTabIndex] = useState(0);\n useEffect(() => {\n // Do all derivations in the same place for now\n // If they were to independently update formData, then both updates would be based on the same initial\n // state of formData, and the second change would clobber the first.\n fmFormRenderProps.setDerivedFormData((draftFormData) => {\n deriveLevelScores({\n levels: draftFormData.levels,\n highScore: formData.challenges?.length,\n autoScoring: formData.autoScoring,\n autoScoringMethod: formData.autoScoringMethod,\n });\n });\n });\n\n useFormToolbar(() => {\n props.setToolbar(\n \n \n \n Edit Twist\n {formData.name}\n \n \n \n \n \n );\n });\n return (\n \n \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n {tabNames[displayTabIndex]}\n
    \n\n \n\n \n\n \n\n \n\n \n fmFormRenderProps.setDerivedFormData((draftDerivedFormData) => {\n draftDerivedFormData.isPublished = true;\n })\n }\n gameType={GAMETYPE}\n />\n
    \n );\n};\n","import * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { NotFound } from \"../../../components/NotFound\";\nimport { notifyError } from \"../../../components/NotificationManager\";\nimport { GameAbstract } from \"../../../domain/serverContract\";\nimport { ComputeEditPage } from \"../games/compute/components/ComputeEditPage\";\nimport { SpellEditPage } from \"../games/spell/components/SpellEditPage\";\nimport { gameAbstractsRecord } from \"../requests/manageGameAbstracts\";\nimport { TwistEditPage } from \"../games/twist/components/TwistEditPage\";\n\nexport interface EditPageProps {\n setToolbar: (element: JSX.Element) => void;\n}\nexport const EditPage = (props: EditPageProps) => {\n const history = useHistory();\n const [gameAbstract, setGameAbstract] = useState(undefined);\n\n const getGameFromPath = async () => {\n // Get id from path\n // */games/edit/\n const tokens = history.location.pathname.split(\"/\");\n const gameId = tokens[tokens.length - 1];\n const gameAbstractsRec = await gameAbstractsRecord();\n const gameAbstract = gameAbstractsRec.gameAbstracts[gameId];\n if (!gameAbstract) {\n // null means not found; undefined means don't know yet\n setGameAbstract(null);\n } else {\n setGameAbstract(gameAbstract);\n }\n };\n useEffect(() => {\n getGameFromPath();\n }, []);\n if (gameAbstract === undefined) {\n return null;\n }\n if (gameAbstract === null) {\n return (\n Game not found. Perhaps it was permanently deleted.\n );\n }\n switch (gameAbstract.gameType) {\n case \"c\":\n return (\n \n );\n case \"s\":\n return (\n \n );\n case \"t\":\n return (\n \n );\n default:\n console.error(`Invalid game type: ${gameAbstract.gameType} `);\n notifyError(`Invalid game type: ${gameAbstract.gameType} `);\n break;\n }\n return ;\n};\n","import {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { deleteTrashedAbstracts } from \"./manageGameAbstracts\";\nimport { GameType } from \"../../../domain/types\";\n\nexport interface EmptyTrashRequest extends ApiRequest {}\n\nexport interface EmptyTrashResponse extends ValidatedApiResponse {}\n\nexport async function emptyTrash(\n request: EmptyTrashRequest\n): Promise {\n return makeCacheValidatedRequest(\n request,\n \"/api/empty_trash\"\n ).then((response) => {\n deleteTrashedAbstracts();\n return response;\n });\n}\n","import Grid from \"@material-ui/core/Grid\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { ConfirmationDialogBase } from \"../../../../../components/dialogTools/ConfirmationDialogBase\";\nimport { makeDialog } from \"../../../../../components/dialogTools/DialogManager\";\nimport { notifyError } from \"../../../../../components/NotificationManager\";\nimport SettingDescription from \"../../../../../components/SettingDescription\";\nimport { FmForm, FmFormRenderProps } from \"../../../../../formManager/FmForm\";\nimport { emptyTrash, EmptyTrashResponse } from \"../../../requests/emptyTrash\";\nimport { gameAbstractsRecord } from \"../../../requests/manageGameAbstracts\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n trashCount: number;\n}\nexport interface EmptyTrashDialogProps {}\n\nexport const makeEmptyTrashDialog = () =>\n makeDialog({\n name: \"EmptyTrashDialog\",\n componentRenderer: (dialogRenderProps) => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n return emptyTrash({ gameType: \"s\" });\n };\n\n const history = useHistory();\n return (\n {\n const record = await gameAbstractsRecord();\n return {\n fmFormDataVersion: undefined,\n trashCount: Object.keys(record.gameAbstracts).length,\n };\n },\n }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => {\n return (\n {\n if (isOkay) {\n // Try to create the game\n return fmProps\n .submit()\n .then((response: EmptyTrashResponse) => {\n dialogRenderProps.close(true, undefined);\n return response;\n })\n .catch((error: Error) => {\n notifyError(error.message);\n });\n } else {\n dialogRenderProps.close(false, undefined);\n }\n }}\n open={true}\n title={\"Empty Trash\"}\n okayText=\"Permanently Empty Trash\"\n >\n \n \n There are {fmProps.formData.trashCount} games in the trash.\n If you empty the trash, then the games will be permanently\n deleted. In addition, they will be \"unpublished\", which\n means that they will be unplayable and all shared progress\n will be deleted.\n \n \n \n );\n }}\n \n );\n },\n });\n","import {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { deleteAbstract } from \"./manageGameAbstracts\";\n\nexport interface DeleteGameRequest extends ApiRequest {\n id: string;\n}\n\nexport interface DeleteGameResponse extends ValidatedApiResponse {}\n\nexport async function deleteGame(\n request: DeleteGameRequest\n): Promise {\n return makeCacheValidatedRequest(\n request,\n \"/api/delete_game\"\n ).then((response) => {\n deleteAbstract(request.id, response.timestamp);\n return response;\n });\n}\n","import {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { trashAbstract } from \"./manageGameAbstracts\";\n\nexport interface TrashGameRequest extends ApiRequest {\n id: string;\n}\n\nexport interface TrashGameResponse extends ValidatedApiResponse {}\n\nexport async function trashGame(\n request: TrashGameRequest\n): Promise {\n return makeCacheValidatedRequest(\n request,\n \"/api/trash_game\"\n ).then((response) => {\n trashAbstract(request.id, response.timestamp);\n return response;\n });\n}\n","import {\n ApiRequest,\n ValidatedApiResponse,\n} from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { untrashAbstract } from \"./manageGameAbstracts\";\n\nexport interface UntrashGameRequest extends ApiRequest {\n id: string;\n name: string;\n}\n\nexport interface UntrashGameResponse extends ValidatedApiResponse {}\n\nexport async function untrashGame(\n request: UntrashGameRequest\n): Promise {\n return makeCacheValidatedRequest(\n request,\n \"/api/untrash_game\"\n ).then((response) => {\n untrashAbstract(request.id, response.timestamp, request.name);\n return response;\n });\n}\n","import { FormControl, makeStyles, Select } from \"@material-ui/core\";\nimport Button from \"@material-ui/core/Button\";\nimport FormControlLabel from \"@material-ui/core/FormControlLabel\";\nimport Grid from \"@material-ui/core/Grid\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport MenuItem from \"@material-ui/core/MenuItem\";\nimport Switch from \"@material-ui/core/Switch\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\nimport DeleteIcon from \"@material-ui/icons/Delete\";\nimport EditIcon from \"@material-ui/icons/Edit\";\nimport MoreVertIcon from \"@material-ui/icons/MoreVert\";\nimport MaterialTable from \"material-table\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { busyPromise } from \"../../../components/BusySpinner\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport { openConfirmationDialog } from \"../../../components/ConfirmationDialog\";\nimport { getDialogMethods } from \"../../../components/dialogTools/DialogManager\";\nimport { useHelp } from \"../../../components/HelpDialog\";\nimport {\n notifyError,\n notifySuccess,\n} from \"../../../components/NotificationManager\";\nimport { PopupMenu } from \"../../../components/PopupMenu\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport SettingSubheader from \"../../../components/SettingSubheader\";\nimport { TellMeMore } from \"../../../components/TellMeMore\";\nimport { getGameUrl } from \"../../../domain/gameUrl\";\nimport { GameAbstract } from \"../../../domain/serverContract\";\nimport {\n GameType,\n getGameTypeIcon,\n getGameTypeLabel,\n} from \"../../../domain/types\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { makeEmptyTrashDialog } from \"../games/shared/components/makeEmptyTrashDialog\";\nimport { deleteGame } from \"../requests/deleteGame\";\nimport {\n gameAbstractsRecord,\n getAbstractsVersion,\n getUniqueName,\n registerTimestampChangeHandler,\n} from \"../requests/manageGameAbstracts\";\nimport { publishGame } from \"../requests/publishGame\";\nimport { templateGame } from \"../requests/templateGame\";\nimport { trashGame } from \"../requests/trashGame\";\nimport { untrashGame } from \"../requests/untrashGame\";\nimport { openAddGameDialog } from \"./AddGameDialog\";\n\nconst useStyles = makeStyles((theme) => ({\n formControl: {\n minWidth: \"6rem\",\n margin: \"0.5rem\",\n },\n}));\n\nexport interface GamesPageProps {}\n\nconst tmm_outdated = \"The game was modified after it was last published.\";\n\nconst MoreActions = (props: {\n gameId: string;\n gameName: string;\n gameType: GameType;\n trashed: boolean;\n isPublished: boolean;\n isTemplate: boolean;\n}) => {\n return (\n \n {\n return [\n {\n if (!props.isPublished) {\n notifyError(\"Publish the game before trying to play it.\");\n return;\n }\n const url = await getGameUrl(\n props.gameType,\n props.gameId,\n props.gameName\n );\n pmProps.close();\n window.open(url);\n }}\n >\n Play\n ,\n {\n const url = await getGameUrl(\n props.gameType,\n props.gameId,\n props.gameName\n );\n navigator.clipboard.writeText(url);\n notifySuccess(\"Copied\");\n pmProps.close();\n }}\n >\n Copy Game URL to Clipboard\n ,\n {\n openAddGameDialog({\n templateGameRef: props.gameId, // use this game as the template\n title: `Create Game (copy of ${props.gameName})`,\n });\n pmProps.close();\n }}\n >\n Clone and Edit\n ,\n {\n busyPromise(\n templateGame({\n id: props.gameId,\n template: !props.isTemplate,\n }).catch((reason) => {\n notifyError(reason.message);\n })\n );\n pmProps.close();\n }}\n >\n {props.isTemplate ? \"Clear Template\" : \"Make Template\"}\n ,\n {\n if (props.trashed) {\n const r = await openConfirmationDialog({\n title: \"Delete Game Permanently\",\n okayText: \"Delete Permanently\",\n content: (\n
    \n When you permanently delete a game from the trash, you\n also unpublish the game so that it can no longer be\n played. This action is not reversible. Press \"Cancel\" to\n go back without making any chnages.\n
    \n ),\n });\n if (r) {\n busyPromise(\n deleteGame({ id: props.gameId }).catch((error) => {\n notifyError(error.message);\n })\n );\n }\n return;\n }\n busyPromise(\n trashGame({ id: props.gameId }).catch((error) => {\n notifyError(error.message);\n })\n );\n pmProps.close();\n }}\n >\n {props.trashed ? \"Delete Permanently\" : \"Delete\"}\n ,\n props.trashed && (\n {\n pmProps.close();\n if (!props.trashed) return;\n busyPromise(\n untrashGame({\n id: props.gameId,\n name: getUniqueName(props.gameName),\n }).catch((error) => {\n notifyError(error.message);\n })\n );\n }}\n >\n Undelete\n \n ),\n ];\n }}\n >\n {(pmProps) => (\n \n \n \n )}\n \n
    \n );\n};\n\ntype GameTypeFilter = GameType | \"any\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n gameAbstractsVersion: string;\n gameAbstracts: GameAbstract[];\n gameTypeFilter: GameTypeFilter;\n}\n\nconst fetchHandler = async (): Promise => {\n const record = await gameAbstractsRecord();\n const gameAbstracts = record.gameAbstracts\n ? Object.values(record.gameAbstracts)\n : [];\n return {\n fmFormDataVersion: undefined,\n gameAbstractsVersion: getAbstractsVersion(),\n gameTypeFilter: \"any\",\n // Copy abstracts.\n // immer will make the props read only when setting form data.\n // managerGameAbstract doesn't use immer to mutate, so it's updates would fail.\n gameAbstracts: gameAbstracts.map((abstract) => {\n return { ...abstract };\n }),\n };\n};\n\nexport const GamesPage: React.FunctionComponent = (props) => {\n useHelp(\"GamesPage\", , true);\n return (\n getAbstractsVersion(),\n }}\n onSubmit={() => Promise.resolve()}\n >\n {(fmFormRenderProps) => {\n return ;\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n}) => {\n const classes = useStyles();\n const fmFormRenderProps = props.fmFormRenderProps;\n const { formData, setFormData } = fmFormRenderProps;\n const history = useHistory();\n const [showDeleted, setShowDeleted] = useState(false);\n useEffect(() => {\n return registerTimestampChangeHandler((version) => {\n setFormData((draft) => {\n draft.gameAbstractsVersion = version;\n });\n });\n }, []);\n useEffect(() => {\n makeEmptyTrashDialog();\n return;\n }, []);\n\n const publish = (rowData: GameAbstract) => {\n busyPromise(\n publishGame({ id: rowData.id, gameType: rowData.gameType }).catch(\n (error) => {\n notifyError(error.message);\n }\n )\n );\n };\n\n const numtrashed = formData.gameAbstracts.reduce((sum, abstract) => {\n if (abstract.trashed && abstract.deleted !== true) sum++;\n return sum;\n }, 0);\n\n const trashSwitch = (\n {\n setShowDeleted(checked);\n }}\n />\n }\n label={`Show Trash (${numtrashed})`}\n />\n );\n const selectGameType = (\n \n ) => {\n setFormData((draft) => {\n draft.gameTypeFilter = event.target.value as GameTypeFilter;\n });\n }}\n >\n Any Game\n Spell\n Compute\n Twist\n \n \n );\n const tableData = formData.gameAbstracts\n // Never show deletes. Show trashed only when asked.\n .filter(\n (abstract) =>\n abstract.deleted !== true &&\n (abstract.trashed ?? false) === showDeleted &&\n (formData.gameTypeFilter === \"any\" ||\n formData.gameTypeFilter === abstract.gameType)\n )\n .map((abstract) =>\n Object.assign(Object.create(null) as GameAbstract, abstract)\n );\n return (\n {\n return (\n
    \n {\n history.push(`/games/edit/${rowData.id}`);\n }}\n >\n \n \n \n
    \n );\n },\n },\n {\n title: \"Name\",\n field: \"name\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n render: (rowData) => {\n if (rowData.template) {\n return (\n \n {rowData.name}\n
    (template)
    \n
    \n );\n }\n return
    {rowData.name}
    ;\n },\n customFilterAndSearch: (searchText: string, rowData) => {\n return match(searchText, rowData);\n },\n },\n {\n title: \"Type\",\n field: \"gameType\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n render: (rowData) => {\n return (\n \n {getGameTypeIcon(rowData.gameType)}\n \n );\n },\n },\n {\n title: \"Title\",\n field: \"title\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n },\n {\n title: \"Subtitle\",\n field: \"subtitle\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n },\n {\n title: \"Description\",\n field: \"description\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n },\n {\n title: (\n \n Players\n \n The number of players is approximate. One is added whenever a\n user loads a different game (of the same or different game type)\n on a different device. So a user will be counted more than once\n if they play on more than one device, or go back to play a\n previous game.\n \n \n ),\n field: \"plays\",\n },\n {\n title: \"Modified\",\n field: \"modified\",\n type: \"datetime\",\n defaultSort: \"desc\",\n customSort: (a1, a2) => {\n return (\n new Date(a1.modified).getTime() - new Date(a2.modified).getTime()\n );\n },\n },\n {\n title: \"Published\",\n field: \"published\",\n type: \"datetime\",\n customSort: (a1, a2) => {\n if (a1.published === a2.published) return 0;\n if (a1.published == null) return 1;\n if (a2.published == null) return -1;\n return (\n new Date(a1.published).getTime() -\n new Date(a2.published).getTime()\n );\n },\n render: (rowData) => {\n if (rowData.published) {\n const t = new Date(rowData.published).toLocaleString();\n const mt = new Date(rowData.modified);\n const pt = new Date(rowData.published);\n if (mt <= pt) {\n return t;\n } else {\n return (\n
    \n
    {t}
    \n
    \n {\n publish(rowData);\n }}\n >\n Publish\n \n \n
    \n
    \n );\n }\n }\n return (\n
    \n
    Unpublished
    \n {\n publish(rowData);\n }}\n >\n Publish\n \n
    \n );\n },\n },\n {\n title: \"Created\",\n field: \"created\",\n type: \"datetime\",\n customSort: (a1, a2) => {\n return (\n new Date(a1.created).getTime() - new Date(a2.created).getTime()\n );\n },\n },\n ]}\n data={tableData}\n options={{\n search: true,\n sorting: true,\n }}\n localization={{\n body: {\n emptyDataSourceMessage: showDeleted\n ? \"No games to display\"\n : \"No games to display (press Create Game to create one!)\",\n },\n }}\n actions={[\n {\n icon: () => selectGameType,\n isFreeAction: true,\n onClick: () => {},\n },\n {\n icon: () => trashSwitch,\n tooltip: \"Show Only Trash\",\n isFreeAction: true,\n onClick: () => {},\n },\n {\n icon: \"deleteForeverIcon\",\n tooltip: \"Empty Trash\",\n isFreeAction: true,\n hidden: !showDeleted || numtrashed == 0,\n onClick: () => {\n getDialogMethods().openByName(\"EmptyTrashDialog\");\n },\n },\n ]}\n />\n );\n};\n\nconst match = (searchText: string, gameAbstract: GameAbstract) => {\n const tokens = searchText.split(\" \");\n for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {\n const token = tokens[tokenIndex].toLowerCase();\n if (token.length === 0) continue;\n\n if (gameAbstract.name.toLowerCase().includes(token)) continue;\n if (gameAbstract.title.toLowerCase().includes(token)) continue;\n if (gameAbstract.subtitle?.toLowerCase().includes(token)) continue;\n if (gameAbstract.description?.toLowerCase().includes(token)) continue;\n\n // Lets user find templates by searching for \"(template)\"\n if (gameAbstract.template && token === \"template\") continue;\n\n if (\n new Date(gameAbstract.modified)\n .toLocaleString()\n .toLowerCase()\n .indexOf(token) >= 0\n )\n continue;\n\n if (\n (gameAbstract.published\n ? new Date(gameAbstract.published).toLocaleString().toLowerCase()\n : \"unpublished\"\n ).indexOf(token) >= 0\n )\n continue;\n\n if (\n new Date(gameAbstract.created)\n .toLocaleString()\n .toLowerCase()\n .indexOf(token) >= 0\n )\n continue;\n\n // If we get here, the token didn't match\n return false;\n }\n return true;\n};\n\nconst VMenu = () => ;\n\nconst MyHelp = () => {\n return (\n \n Find a Game\n \n To find a game, either click a column title to sort or type search text\n in the search box. By default, the most recently modified games are on\n top, which makes it easy to find recently modified games.\n \n Edit a Game\n \n To edit a game, click . The game will open in the editor so\n that you can change it.\n \n Publish a Game\n \n If a game has not been published, or if it was modified after being\n publish, then a PUBLISH button appears in the Published column of the\n table. To publish the game, click PUBLISH. To get the game URL to share,\n click and choose Copy Game URL to Clipboard.\n \n How Much Has My Game Been Played?\n \n Look at the number in the Players column. That's an estimate of the\n number of different people who played that game. Players will be counted\n more than once if they play the game on different devices or in\n different browsers.\n \n Copy a Game\n \n To copy a game, click and choose Clone and Edit. The game will\n open in the editor so that you can change it.\n \n Play a Game\n \n To delete a game, click and choose Play. The game will open in\n a new browser tab. You must publish a game to play it.\n \n Delete a Game\n \n To delete a game, click and choose Delete. The game will be\n moved to the trash. You can restore games in the trash. Players may\n continue to play deleted games.\n \n Restore a Deleted\n \n Click SHOW TRASH to see the deleted games. To restore a game, click\n and choose Undelete.\n \n Permanently Delete a Game\n \n Click SHOW TRASH to see the deleted games. Click\n and choose Delete Permanently. The game and all share progress\n will be permanently deleted. There is no way to restore permanently\n deleted games. Once a game is permanently deleted, it can no longer be\n played. You can permanently deleted all games in the trash by emptying\n the trash .\n \n \n );\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeCacheValidatedRequest } from \"./makeCacheValidatedRequest\";\nimport { updateAbstract } from \"./manageGameAbstracts\";\n\nexport interface TemplateGameRequest {\n id: string;\n template: boolean;\n}\n\nexport interface TemplateGameResponse extends ApiResponseHeader {}\n\n// templateGame makes this game the template for its game type (or clears)\nexport async function templateGame(request: TemplateGameRequest) {\n return makeCacheValidatedRequest(request, \"/api/template_game\").then(\n (response) => {\n updateAbstract(request.id, (abstract) => {\n abstract.template = request.template;\n });\n return response;\n }\n );\n}\n","import Button from \"@material-ui/core/Button\";\nimport ImportIcon from \"@material-ui/icons/CloudDownload\";\nimport * as React from \"react\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\n\ninterface ImportGameButtonProps {\n onClick?: () => void;\n}\n\nexport const ImportGameButton: React.FunctionComponent = (\n props\n) => {\n return (\n \n }\n onClick={props.onClick}\n >\n Import Game\n \n \n );\n};\n","import {\n ApiResponse,\n GameAbstractsRecord,\n} from \"../../../domain/serverContract\";\nimport { makeRequestWithAuthentication } from \"../../../http/authenticated\";\n\nexport interface GetLibraryAbstractsRecordRequest {}\n\nexport interface GetLibraryAbstractsRecordResponse extends ApiResponse {\n gameAbstractsRecord: GameAbstractsRecord;\n}\n\nasync function getLibraryAbstractsRecord(): Promise<\n GetLibraryAbstractsRecordResponse\n> {\n return makeRequestWithAuthentication({}, \"/api/get_library_abstracts_record\");\n}\n\nlet libraryAbstractsRecordCache: GameAbstractsRecord;\nlet promiseCache: Promise;\n\nexport const libraryAbstractsRecord = async () => {\n if (promiseCache) return promiseCache;\n\n promiseCache = getLibraryAbstractsRecord()\n .then((response) => {\n if (response.gameAbstractsRecord.gameAbstracts == null) {\n response.gameAbstractsRecord.gameAbstracts = {};\n }\n // Denormalize game ID from map key\n response.gameAbstractsRecord.gameAbstracts &&\n Object.keys(response.gameAbstractsRecord.gameAbstracts).map((key) => {\n response.gameAbstractsRecord.gameAbstracts[key].id = key;\n });\n libraryAbstractsRecordCache = response.gameAbstractsRecord;\n // The cache is capture via closure, so when we update the cache we update the promise result.\n return libraryAbstractsRecordCache;\n })\n .catch((error) => {\n promiseCache = undefined;\n throw error;\n });\n return promiseCache;\n};\n","import MoreVertIcon from \"@material-ui/icons/MoreVert\";\nimport MaterialTable from \"material-table\";\nimport * as React from \"react\";\nimport { useEffect } from \"react\";\nimport { SubtleButton } from \"../../../components/buttons\";\nimport { useHelp } from \"../../../components/HelpDialog\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport SettingSubheader from \"../../../components/SettingSubheader\";\nimport { getGameUrl } from \"../../../domain/gameUrl\";\nimport { GameAbstract } from \"../../../domain/serverContract\";\nimport {\n getGameTypeIcon,\n getGameTypeLabel,\n GameType,\n} from \"../../../domain/types\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { makeEmptyTrashDialog } from \"../games/shared/components/makeEmptyTrashDialog\";\nimport {\n getAbstractsVersion,\n registerTimestampChangeHandler,\n} from \"../requests/manageGameAbstracts\";\nimport { libraryAbstractsRecord } from \"../requests/manageLibraryAbstracts\";\nimport { openAddGameDialog } from \"./AddGameDialog\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\nimport { FormControl, makeStyles, Select, MenuItem } from \"@material-ui/core\";\nconst useStyles = makeStyles((theme) => ({\n formControl: {\n minWidth: \"6rem\",\n margin: \"0.5rem\",\n },\n}));\n\nexport interface LibraryPageProps {}\n\ntype GameTypeFilter = GameType | \"any\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n gameAbstractsVersion: string;\n gameAbstracts: GameAbstract[];\n gameTypeFilter: GameTypeFilter;\n}\n\nconst fetchHandler = async (): Promise => {\n const record = await libraryAbstractsRecord();\n const gameAbstracts = record.gameAbstracts\n ? Object.values(record.gameAbstracts)\n : [];\n return {\n fmFormDataVersion: undefined,\n gameAbstractsVersion: getAbstractsVersion(),\n gameTypeFilter: \"any\",\n // Copy abstracts.\n // immer will make the props read only when setting form data.\n // managerGameAbstract doesn't use immer to mutate, so it's updates would fail.\n gameAbstracts: gameAbstracts.map((abstract) => {\n return { ...abstract };\n }),\n };\n};\n\nexport const LibraryPage: React.FunctionComponent = () => {\n useHelp(\"LibraryPage\", , true);\n return (\n getAbstractsVersion(),\n }}\n onSubmit={() => Promise.resolve()}\n >\n {(fmFormRenderProps) => {\n return ;\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n}) => {\n const classes = useStyles();\n const fmFormRenderProps = props.fmFormRenderProps;\n const { formData, setFormData } = fmFormRenderProps;\n useEffect(() => {\n return registerTimestampChangeHandler((version) => {\n setFormData((draft) => {\n draft.gameAbstractsVersion = version;\n });\n });\n }, []);\n useEffect(() => {\n makeEmptyTrashDialog();\n return;\n }, []);\n const selectGameType = (\n \n ) => {\n setFormData((draft) => {\n draft.gameTypeFilter = event.target.value as GameTypeFilter;\n });\n }}\n >\n Any Game\n Spell\n Compute\n Twist\n \n \n );\n const tableData = formData.gameAbstracts\n .filter(\n (abstract) =>\n formData.gameTypeFilter === \"any\" ||\n formData.gameTypeFilter === abstract.gameType\n )\n .map((abstract) =>\n Object.assign(Object.create(null) as GameAbstract, abstract)\n );\n return (\n {\n return (\n
    \n {\n const url = await getGameUrl(\n rowData.gameType,\n rowData.id,\n rowData.name\n );\n window.open(url);\n }}\n >\n Play\n \n {\n openAddGameDialog({\n gameType: rowData.gameType,\n templateGameRef: rowData.id, // use this game as the template\n title: \"Import Game from Library\",\n gameName: rowData.name,\n });\n }}\n >\n Import\n \n
    \n );\n },\n },\n {\n title: \"Type\",\n field: \"gameType\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n render: (rowData) => {\n return (\n \n {getGameTypeIcon(rowData.gameType)}\n \n );\n },\n customFilterAndSearch: (searchText: string, rowData) => {\n return match(searchText, rowData);\n },\n },\n {\n title: \"Title\",\n field: \"title\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n },\n {\n title: \"Subtitle\",\n field: \"subtitle\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n },\n {\n title: \"Description\",\n field: \"description\",\n cellStyle: {\n wordBreak: \"normal\",\n },\n },\n {\n title: \"Published\",\n field: \"published\",\n type: \"datetime\",\n defaultSort: \"desc\",\n customSort: (a1, a2) => {\n return (\n new Date(a1.published).getTime() -\n new Date(a2.published).getTime()\n );\n },\n },\n ]}\n data={tableData}\n options={{\n search: true,\n sorting: true,\n }}\n localization={{\n body: {\n emptyDataSourceMessage: \"No games in the library\",\n },\n }}\n actions={[\n {\n icon: () => selectGameType,\n isFreeAction: true,\n onClick: () => {},\n },\n ]}\n />\n );\n};\n\nconst match = (searchText: string, gameAbstract: GameAbstract) => {\n const tokens = searchText.split(\" \");\n for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {\n const token = tokens[tokenIndex].toLowerCase();\n if (token.length === 0) continue;\n\n if (gameAbstract.name.toLowerCase().includes(token)) continue;\n if (gameAbstract.title.toLowerCase().includes(token)) continue;\n if (gameAbstract.subtitle?.toLowerCase().includes(token)) continue;\n if (gameAbstract.description?.toLowerCase().includes(token)) continue;\n\n if (\n (gameAbstract.published\n ? new Date(gameAbstract.published).toLocaleString().toLowerCase()\n : \"unpublished\"\n ).indexOf(token) >= 0\n )\n continue;\n\n // If we get here, the token didn't match\n return false;\n }\n return true;\n};\n\nconst MyHelp = () => {\n return (\n \n Find a Game\n \n To find a game, either click a column title to sort or type search text\n in the search box. By default, the most recently published games are on\n top, which makes it easy to find recently added games.\n \n Play Game\n \n To try a game before importing it, click the PLAY button. The game will\n open in another browser tab, where you can play it.\n \n Import Game\n \n To import a game, click the IMPORT button. The game will open in the\n editor so that you can change it, and it will appear on your games page.\n \n \n );\n};\n","import MoreVertIcon from \"@material-ui/icons/MoreVert\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { SecondaryButton, SubtleButton } from \"../../../components/buttons\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { GameType, getGameTypeLabel } from \"../../../domain/types\";\nimport { gameAbstractsRecord } from \"../requests/manageGameAbstracts\";\n\nexport interface TemplateSettingsProps {\n gameType: GameType;\n}\nexport const TemplateSettings: React.FunctionComponent = (\n props\n) => {\n const [templateName, setTemplateName] = useState(undefined);\n // undefined templateId means not yet fetched, null means no template\n const [templateId, setTemplateId] = useState(undefined);\n useEffect(() => {\n gameAbstractsRecord().then((abstractsRecord) => {\n const templateId = Object.keys(abstractsRecord.gameAbstracts).find(\n (gameId) => {\n const abstract = abstractsRecord.gameAbstracts[gameId];\n return abstract.template && abstract.gameType === props.gameType;\n }\n );\n const abstract = abstractsRecord.gameAbstracts[templateId];\n if (templateId) {\n setTemplateName(abstract.name);\n setTemplateId(templateId);\n } else {\n setTemplateId(null);\n }\n });\n }, []);\n const history = useHistory();\n const gameTypeLabel = getGameTypeLabel(props.gameType);\n return (\n \n {templateName && (\n <>\n \n To view or change your current template(\n {templateName}), press the button below.\n \n {\n history.push(`/games/edit/${templateId}`);\n }}\n >\n Go To My {gameTypeLabel} Game Template\n \n \n )}\n {!templateName && (\n \n You have no game template. To create one, find a game on the\n {\n history.push(`/games`);\n }}\n >\n Games search page\n \n , and choose \"Make Template\" from the command menu (\n ) next to the game.\n \n )}\n \n );\n};\n","import * as React from \"react\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport SettingHeader from \"../../../components/SettingHeader\";\nimport { TemplateSettings } from \"./TemplateSettings\";\nimport { SpellIcon } from \"../../../components/icons/SpellIcon\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { ComputeIcon } from \"../../../components/icons/ComputeIcon\";\nimport { TwistIcon } from \"../../../components/icons/TwistIcon\";\nimport { useHelp } from \"../../../components/HelpDialog\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport SettingSubheader from \"../../../components/SettingSubheader\";\nimport SettingDescription from \"../../../components/SettingDescription\";\n\nexport const TemplatesPage = () => {\n useHelp(\"TemplatesPage\", , true);\n return (\n \n \n \n \n Spell Template\n \n \n \n \n \n \n Compute Template\n \n \n \n \n \n \n Twist Template\n \n \n \n \n );\n};\n\nconst MyHelp = () => {\n return (\n \n Templates\n \n The templates page shows the current (if any) template for each game\n type. When you create a new game, its configuration comes from the\n template for its game type.\n \n \n );\n};\n","import List from \"@material-ui/core/List\";\nimport ListItem from \"@material-ui/core/ListItem\";\nimport ListItemIcon from \"@material-ui/core/ListItemIcon\";\nimport ListItemText from \"@material-ui/core/ListItemText\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Toolbar from \"@material-ui/core/Toolbar\";\nimport Typography from \"@material-ui/core/Typography\";\nimport AddIcon from \"@material-ui/icons/Add\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { Route, Switch, useHistory, useRouteMatch } from \"react-router-dom\";\nimport { GamesIcon } from \"../../../components/icons/GamesIcon\";\nimport { LibraryIcon } from \"../../../components/icons/LibraryIcon\";\nimport { notifyError } from \"../../../components/NotificationManager\";\nimport { Title } from \"../../../components/Title\";\nimport { openImportGameDialog } from \"../games/shared/components/ImportGameDialog\";\nimport { openAddGameDialog } from \"./AddGameDialog\";\nimport { CreateGameButton } from \"./CreateGameButton\";\nimport { EditPage } from \"./EditPage\";\nimport { GamesPage } from \"./GamesPage\";\nimport { ImportGameButton } from \"./ImportGameButton\";\nimport { LibraryPage } from \"./LibraryPage\";\nimport { TemplatesPage } from \"./TemplatesPage\";\nimport { TopicFrame } from \"./TopicFrame\";\n\nconst drawerWidth = 240;\nconst useStyles = makeStyles((theme: Theme) => {\n const c = createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n appBar: {\n zIndex: theme.zIndex.drawer + 1,\n },\n drawer: {\n width: drawerWidth,\n flexShrink: 0,\n },\n drawerPaper: {\n width: drawerWidth,\n // position: \"static\",\n },\n drawerContainer: {\n overflow: \"auto\",\n },\n content: {\n flexGrow: 1,\n padding: theme.spacing(3),\n },\n nested: {\n paddingLeft: theme.spacing(4),\n },\n // Loads information about the app bar, including app bar height\n toolbar: theme.mixins.toolbar,\n });\n return c;\n});\n\nenum Page {\n Games,\n Templates,\n Library,\n Edit,\n}\n\nexport interface GamesTopicProps {}\n\nexport const GamesTopic: React.FunctionComponent = (props) => {\n const classes = useStyles();\n const [editorToolbar, setEditorToolbar] = useState(null);\n const [templatesToolbar, setTemplatesToolbar] = useState(\n Templates\n );\n const history = useHistory();\n let { path } = useRouteMatch();\n\n const leftNav = (\n \n history.push(`${path}/games`)}>\n \n \n \n \n \n history.push(`${path}/templates`)}>\n \n \n \n \n \n history.push(`${path}/library`)}>\n \n \n \n \n \n \n );\n\n const gamesToolbar = (\n \n \n Games\n \n openAddGameDialog({ title: \"Create Game\" })}\n >\n Create Game\n \n openImportGameDialog({})}>\n Import Game\n \n \n );\n\n const [page, setPage] = useState(Page.Games);\n\n // A path of /games/edit/* goes to the editor\n useEffect(() => {\n const locpath = history.location.pathname;\n switch (locpath) {\n case `${path}/games`:\n case `${path}`:\n setPage(Page.Games);\n break;\n case `${path}/templates`:\n setPage(Page.Templates);\n break;\n case `${path}/library`:\n setPage(Page.Library);\n break;\n default:\n if (locpath.startsWith(`${path}/edit`)) {\n setPage(Page.Edit);\n } else {\n notifyError(\"Could not find page.\");\n }\n break;\n }\n }, [history.location.pathname]);\n return (\n <>\n {\n history.push(`${path}/games`);\n }}\n >\n \n \n }\n appIconMenuText=\"Games\"\n leftNav={leftNav}\n toolbar={\n page === Page.Games ? (\n gamesToolbar\n ) : page === Page.Templates ? (\n {templatesToolbar}\n ) : (\n editorToolbar\n )\n }\n >\n \n {\n return (\n <>\n \n \n );\n }}\n />\n {\n return ;\n }}\n />\n {\n return ;\n }}\n />\n {\n return ;\n }}\n />\n {\n return ;\n }}\n />\n \n \n \n );\n};\n","import { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { PrimaryButton, SubtleButton } from \"../../../components/buttons\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport {\n notifyError,\n notifySuccess,\n} from \"../../../components/NotificationManager\";\nimport Title from \"../../../components/Title\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n email: string;\n password: string;\n}\n\nconst initialFormData: FormData = {\n fmFormDataVersion: 0,\n email: \"\",\n password: \"\",\n};\n\nexport interface LoginProps {}\n\nexport const Login = () => {\n const history = useHistory();\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n firebaseauth()\n .setPersistence(firebaseauth.Auth.Persistence.LOCAL)\n .then(() =>\n firebaseauth()\n .signInWithEmailAndPassword(formData.email, formData.password)\n .then((_userCredential) => {\n // replace, not push, so that BACK doesn't go back to the login page\n // But if we came from the logoff page, go home instead!\n const redirectPath = history.location.pathname;\n history.replace(\n redirectPath === \"/logoff\" || redirectPath === \"/login\"\n ? \"/\"\n : redirectPath\n );\n })\n )\n .catch(function () {\n notifyError(\"Login failed. Check the email address and password.\");\n });\n };\n return (\n Promise.resolve(initialFormData) }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => (\n \n Login\n \n name=\"email\"\n initialFocus\n width=\"25rem\"\n textFieldProps={{\n InputProps: {\n spellCheck: false,\n },\n }}\n />\n \n name=\"password\"\n width=\"25rem\"\n textFieldProps={{\n type: \"Password\",\n }}\n />\n fmProps.submit()}\n disabled={fmProps.isSubmitting}\n >\n Login\n \n {\n if (fmProps.formData.email === \"\") {\n notifyError(\n \"Enter an email address before requesting a new password.\"\n );\n return;\n }\n firebaseauth()\n .sendPasswordResetEmail(fmProps.formData.email)\n .then(() => {\n notifySuccess(\n \"Check your email (and spam folder) for the password reset email.\"\n );\n })\n .catch((error) => {\n notifyError(error);\n });\n }}\n disabled={fmProps.isSubmitting}\n >\n Send password reset email\n \n \n )}\n \n );\n};\n","import Link from \"@material-ui/core/Link\";\nimport { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { notifyError } from \"../../../components/NotificationManager\";\nimport { PageContainer } from \"../../../components/PageContainer\";\n\ninterface LogoffProps {}\n\nexport const Logoff = (props: LogoffProps) => {\n const [loggedOff, setLoggedOff] = useState(false);\n const [logoffError, setLogoffError] = useState(false);\n const fa = firebaseauth();\n if (fa.currentUser) {\n if (logoffError) {\n return (\n \n Logoff failed. Click{\" \"}\n {\n setLogoffError(false);\n }}\n >\n login\n {\" \"}\n to try to logoff again.\n \n );\n }\n firebaseauth()\n .signOut()\n .then(() => {\n setLoggedOff(true);\n })\n .catch((reason) => {\n setLogoffError(true);\n notifyError(\"Logoff failed\");\n });\n return Logoff in progress...;\n }\n return (\n \n You are no longer logged in. Click login to\n log in again.\n \n );\n};\n","import * as React from \"react\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport Title from \"../../../components/Title\";\nimport SettingHeader from \"../../../components/SettingHeader\";\nimport SettingDescription from \"../../../components/SettingDescription\";\n\nexport const Privacy = () => {\n return (\n \n Privacy Policy\n \n This privacy policy describes what we do with your data when you use\n Cortex Author (\"the App\"). It is effective as of 13 August 2020.\n Questions about this policy should be emailed to privacy @\n cortexplay.com.\n
      \n
    • \n We ask for your name, email address, and initials for the following\n purposes:\n
        \n
      • \n We ask for your email address in order to keep track of your\n authored games for you, and to communicate with you about your\n account. We may also let you know about changes to the App, and\n we may send you marketing email.\n
      • \n
      • \n We ask for your name and initials in order to address you\n politely.\n
      • \n
      \n
    • \n
    • \n We do not share your email address, name, or initials -- or any\n other information that might be personally identifiable -- with any\n other organization.\n
    • \n
    • \n We collect information that helps us provide a reliable service,\n such as the type of device and browser you use, and the IP address\n from which you access the App.\n
    • \n
    • \n We do collect information that helps us improve the quality of the\n App, such as which features you use.\n
    • \n
    \n
    \n Data\n \n The App data is processed on your devices and on the Google Cloud in the\n United States. The Google Cloud is the only data processor. If you\n cancel your subscription, then we may retain your data for a short\n period of time (a few weeks or less) in case you decided to reactivate\n your subscription. After that period of time, we will purge all of your\n data except for data related to subscription payments and offline\n backups.\n \n
    \n );\n};\n","import { useState } from \"react\";\nimport { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { UserProfile } from \"../../../domain/types\";\nimport { useIsMounted } from \"../../../hooks/useIsMounted\";\nimport { makeRequestWithAuthentication } from \"../../../http/authenticated\";\nimport { getAuthIdToken } from \"../components/RouterTop\";\n\nexport const useUserProfile = () => {\n const isMountedRef = useIsMounted();\n const [userProfile, setUserProfile] = useState({\n displayName: \"Cortex User\",\n initials: \"\",\n });\n getUserProfile().then((up) => {\n // Somehow, the then clause may be executed before the userProfile record is received.\n // I don't know why.\n // I should not need to set a null replacement value for userProfile here.\n // Don't set state unless it has really changed.\n if (!up && userProfile.displayName === \"\") return;\n if (!up.initials) up.initials = up.displayName[0];\n if (up) {\n if (\n up.displayName === userProfile.displayName &&\n up.initials === userProfile.initials\n ) {\n return;\n }\n }\n isMountedRef.current &&\n setUserProfile(up ?? { displayName: \"\", initials: \"\" });\n });\n return userProfile;\n};\n\nlet promiseCache: Promise;\n\nexport const getUserProfile = async () => {\n const idToken = await getAuthIdToken();\n const up: UserProfile = { initials: \"\", displayName: \"\" };\n if (!idToken) return Promise.resolve(up);\n if (promiseCache) return promiseCache;\n promiseCache = gUserProfile()\n .then((response) => {\n return response.userProfile;\n })\n .catch((error) => {\n promiseCache = undefined;\n throw error;\n });\n return promiseCache;\n};\n\n// We get it back because the server may have changed it\ninterface SaveUserProfileResponse extends ApiResponseHeader {\n userProfile: UserProfile;\n}\n\n// Saves settings to the database\n// Updates cache if save is successful\nexport async function saveUserProfile(\n mutator: (draftUserProfile: UserProfile) => void\n): Promise {\n const up = await getUserProfile();\n mutator(up);\n const response = await makeRequestWithAuthentication(\n { userProfile: up },\n \"/api/save_user_profile\"\n );\n promiseCache = Promise.resolve(up);\n return response;\n}\n\ninterface GetUserProfileResponse extends ApiResponseHeader {\n userProfile: UserProfile;\n}\nasync function gUserProfile(): Promise {\n return makeRequestWithAuthentication({}, \"/api/get_user_profile\");\n}\n","import * as React from \"react\";\nimport { useContext } from \"react\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { getUserProfile, saveUserProfile } from \"../requests/manageUserProfile\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport { UserContext } from \"./RouterTop\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingHeader from \"../../../components/SettingHeader\";\nimport { Title } from \"../../../components/Title\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n displayName: string;\n initials: string;\n}\n\nexport interface ProfileProps {}\n\nexport const Profile = () => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n const response = await saveUserProfile((draftUserProfile) => {\n draftUserProfile.initials = formData.initials;\n draftUserProfile.displayName = formData.displayName;\n });\n fmFormRenderProps.setFormData((draftFormData) => {\n draftFormData.initials = response.userProfile.initials;\n });\n };\n const authUserInfo = useContext(UserContext);\n return (\n {\n const up = await getUserProfile();\n return {\n initials: up.initials ?? \"\",\n displayName: up.displayName ?? \"\",\n fmFormDataVersion: 0,\n };\n },\n }}\n onSubmit={handleSubmit}\n >\n {(fmProps) => (\n \n Profile for {authUserInfo.email}\n Display Name\n \n The display name is used to address you within the authoring tool,\n and in emails.\n \n \n name=\"displayName\"\n width=\"30rem\"\n initialFocus\n isRequired\n maxLength={50}\n />\n Initials\n \n The initials are used to identify you when there is not room for\n your display name.\n \n \n name=\"initials\"\n width=\"30rem\"\n maxLength={2}\n isRequired\n />\n fmProps.submit()}\n disabled={fmProps.isSubmitting || fmProps.isDirty !== true}\n >\n Save\n \n \n )}\n \n );\n};\n","import * as React from \"react\";\nimport { useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { FmTextField } from \"../../../formManager/FmField\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { getConfiguration } from \"../requests/getConfiguration\";\nimport { registerNewUser } from \"../requests/registerNewUser\";\nimport { PrimaryButton } from \"../../../components/buttons\";\nimport ExplanatoryNote from \"../../../components/ExplanatoryNote\";\nimport { InfoDialog } from \"../../../components/dialogTools/InfoDialog\";\nimport { notifyError } from \"../../../components/NotificationManager\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport PageIntro from \"../../../components/PageIntro\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport { Title } from \"../../../components/Title\";\n\ndeclare var CP_RECAPTCHAReady: boolean;\ndeclare var grecaptcha: any;\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n email: string;\n displayName: string;\n recaptchaValue: string;\n recaptchaSiteKey: string;\n}\n\nconst initialFormData: FormData = {\n fmFormDataVersion: 0,\n email: \"\",\n displayName: \"\",\n recaptchaValue: \"\",\n recaptchaSiteKey: \"\",\n};\n\ninterface RegisterProps {}\n\nexport const Register = () => {\n const history = useHistory();\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const { email, displayName, recaptchaValue } = fmFormRenderProps.formData;\n if ((recaptchaValue ?? \"\") === \"\") {\n notifyError(\"You must first complete the robot challenge.\");\n return;\n }\n localStorage.setItem(\"emailForSignIn\", email);\n return registerNewUser({\n email,\n displayName,\n recaptcha: recaptchaValue,\n }).then(() => history.push(\"/registrationsubmitted\"));\n };\n return (\n \n getConfiguration().then((config) => {\n return {\n ...initialFormData,\n recaptchaSiteKey: config.recaptchaSiteKey,\n };\n }),\n }}\n onSubmit={handleSubmit}\n suppressPrompt\n >\n {(fmProps) => {\n const [forceUpdate, setForceUpdate] = useState(0);\n React.useEffect(() => {\n if (CP_RECAPTCHAReady == null) {\n // Wait for the recaptcha component to load\n // After we've tried a bunch of times, quit\n if (forceUpdate > 20) {\n notifyError(\n \"Having trouble loading recaptcha test. There may be a network issue.\"\n );\n return;\n }\n setTimeout(() => setForceUpdate(forceUpdate + 1), 250);\n }\n });\n React.useEffect(() => {\n if (!CP_RECAPTCHAReady) return;\n const newDiv = document.getElementById(\"recaptcha_node\");\n grecaptcha.render(newDiv, {\n sitekey: fmProps.formData.recaptchaSiteKey,\n callback: (value: string) => {\n fmProps.setFormData((draft) => {\n draft.recaptchaValue = value;\n });\n },\n });\n }, [CP_RECAPTCHAReady]);\n\n return (\n \n Register\n \n Registration is easy. Provide your email and name. We'll send you\n an email with a confirmation link. Once you click the confirmation\n link and create a password, you will be registered -- and your\n free trial will start.\n \n \n If you don't see the email in your inbox, check your spam folder.\n \n \n name=\"email\"\n initialFocus\n isRequired\n width=\"25rem\"\n textFieldProps={{\n InputProps: {\n spellCheck: false,\n },\n }}\n />\n \n The display name is used to address you within the application,\n and in emails.\n \n \n name=\"displayName\"\n isRequired\n width=\"25rem\"\n textFieldProps={{\n InputProps: {\n spellCheck: false,\n },\n }}\n />\n\n
    \n fmProps.submit()}\n disabled={fmProps.isSubmitting}\n >\n Send Registration Email\n \n
    \n );\n }}\n \n );\n};\n\nexport const RegistrationSubmitted = () => {\n return (\n \n Almost Registered!\n \n Please check your inbox (and spam folder) for your registration email.\n Until you click the link in the registration email and complete the\n registration process, there will be nothing more to do in this app.\n \n \n );\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeRequest } from \"../../../http/http\";\n\nexport interface RegisterNewUserRequest {\n email: string;\n displayName: string;\n recaptcha: string;\n}\n\nexport interface RegisterNewuserResponse extends ApiResponseHeader {}\n\nexport async function registerNewUser(\n request: RegisterNewUserRequest\n): Promise {\n return makeRequest(request, \"/api/register_new_user\");\n}\n","import { IconButton, InputAdornment, TextField } from \"@material-ui/core\";\nimport DeleteIcon from \"@material-ui/icons/HighlightOff\";\nimport * as React from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport { SecondaryButton, SubtleButton } from \"../../../components/buttons\";\nimport PageIntro from \"../../../components/PageIntro\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { TellMeMore } from \"../../../components/TellMeMore\";\nimport ToolbarTitle from \"../../../components/ToolbarTitle\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport { useFormToolbar } from \"../../../formManager/useFormToolbar\";\nimport { useFreshState } from \"../../../hooks/useFreshState\";\nimport { makeSeparatedStringFromList, union } from \"../../../utilities\";\nimport { openAddWordsDialog } from \"../games/spell/components/AddWordsDialog\";\nimport { VirtualizedWordList } from \"../games/spell/components/VirtualizedWordList\";\nimport {\n saveUserGameSettings,\n userGameSettings,\n} from \"../requests/manageUserGameSettings\";\nimport { FormToolbarEditorButtons } from \"./FormToolbarEditorButtons\";\nimport { validateWords } from \"./HiddenWordsPage\";\nimport { notifySuccess } from \"../../../components/NotificationManager\";\n\nexport interface FormData {\n fmFormDataVersion: number; // required by FmForm\n extraWords: string[];\n hiddenWords: string[]; // need for validation when adding words\n}\n\nexport interface ExtraWordsPageProps {\n setToolbar: (element: JSX.Element) => void;\n}\nexport const ExtraWordsPage = (props: ExtraWordsPageProps) => {\n const handleSubmit = async (\n fmFormRenderProps: FmFormRenderProps\n ) => {\n const formData = fmFormRenderProps.formData;\n return saveUserGameSettings((userGameSettings) => {\n userGameSettings.extraWords = formData.extraWords;\n });\n };\n\n return (\n {\n const settings = await userGameSettings();\n return {\n fmFormDataVersion: undefined,\n extraWords: settings.extraWords,\n hiddenWords: settings.hiddenWords,\n };\n },\n }}\n onSubmit={handleSubmit}\n >\n {(fmFormRenderProps) => {\n return (\n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n setToolbar: (element: JSX.Element) => void;\n}) => {\n const fmFormRenderProps = props.fmFormRenderProps;\n const extraWords = fmFormRenderProps.formData.extraWords;\n const [getFilter, setFilter] = useFreshState(() => \"\");\n const ref = useRef(null);\n useEffect(() => {\n const inputElement: HTMLInputElement = ref.current;\n if (inputElement) inputElement.focus();\n }, []);\n const filteredWords = fmFormRenderProps.formData.extraWords\n .filter((word) => word.indexOf(getFilter()) >= 0)\n .sort();\n\n useFormToolbar(() => {\n props.setToolbar(\n \n Spell: Extra Words\n \n \n );\n });\n\n return (\n \n \n The words in this list will be added to the built-in dictionary when\n finding game words.\n \n The built-in dictionary may not include recent or less-common words.\n When searching, a word is found only if that word is\n
      \n
    • \n in the built-in dictionary and is not excluded by virtue of being\n on the built-in sensitive word list\n
    • \n
    • OR is in your extra words list (on this page)
    • \n
    • AND is not in your hidden words list.
    • \n
    \n You won't be able to add words that are in your hidden words list\n because they would be ignored.\n
    \n

    \n To share with others:\n {\n navigator.clipboard.writeText(\n makeSeparatedStringFromList(filteredWords)\n );\n notifySuccess(\"Copied\");\n }}\n >\n Copy words to clipboard\n \n

    \n
    \n \n \n openAddWordsDialog({\n title: \"Add Extra Words\",\n submitHandler: (words) => {\n const errorMessage = validateWords(\n words,\n [], // don't send extra words -- prevents rejection for dups\n \"extra\",\n fmFormRenderProps.formData.hiddenWords,\n \"hidden\"\n );\n if (errorMessage) return Promise.reject(errorMessage);\n fmFormRenderProps.setFormData((draftFormData) => {\n draftFormData.extraWords = union(extraWords, words);\n draftFormData.extraWords.sort((a, b) =>\n a < b ? -1 : a > b ? 1 : 0\n );\n });\n return Promise.resolve();\n },\n })\n }\n >\n Add Words\n \n {\n fmFormRenderProps.setFormData((draftFormData) => {\n filteredWords.forEach((filteredWord) => {\n const index = draftFormData.extraWords.indexOf(filteredWord);\n draftFormData.extraWords.splice(index, 1);\n });\n });\n }}\n >\n Delete {filteredWords.length} Word\n {`${filteredWords.length !== 1 ? \"s\" : \"\"} Below`}\n \n \n \n As you type into the word filter, you will see only matching words. If\n you use the DELETE button it will delete only the matching words.\n \n
    \n \n {\n setFilter(\"\");\n }}\n >\n \n \n \n ),\n style: { maxWidth: \"20rem\" },\n }}\n onChange={(event) => {\n const ftext: string = event.currentTarget.value;\n setFilter(ftext);\n }}\n />\n
    \n\n
    \n {\n // So we also need to update form data -- which is also what dirties the page.\n fmFormRenderProps.setFormData((draftFormData) => {\n const delIndex = draftFormData.extraWords.indexOf(word);\n draftFormData.extraWords.splice(delIndex, 1);\n });\n }}\n />\n
    \n
    \n );\n};\n","import Grid from \"@material-ui/core/Grid\";\nimport * as React from \"react\";\nimport { useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { FmForm, FmFormRenderProps } from \"../../../formManager/FmForm\";\nimport {\n userGameSettings,\n saveUserGameSettings,\n} from \"../requests/manageUserGameSettings\";\nimport { useFormToolbar } from \"../../../formManager/useFormToolbar\";\nimport ToolbarTitle from \"../../../components/ToolbarTitle\";\nimport { FormToolbarEditorButtons } from \"./FormToolbarEditorButtons\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport SettingHeader from \"../../../components/SettingHeader\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport Emphasize from \"../../../components/Emphasize\";\nimport { TellMeMore } from \"../../../components/TellMeMore\";\nimport { FmSwitchField } from \"../../../formManager/FmField\";\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n includeSensitiveWords: boolean;\n}\n\nexport interface SensitiveWordsPageProps {\n setToolbar: (element: JSX.Element) => void;\n}\nexport const SensitiveWordsPage = (props: SensitiveWordsPageProps) => {\n const [templateName, setTemplateName] = useState(undefined);\n return (\n {\n const settings = await userGameSettings();\n return {\n fmFormDataVersion: undefined,\n includeSensitiveWords: settings.includeSensitiveWords,\n };\n },\n }}\n onSubmit={async (fmFormRenderProps: FmFormRenderProps) => {\n const formData = fmFormRenderProps.formData;\n return saveUserGameSettings((userGameSettings) => {\n userGameSettings.includeSensitiveWords =\n formData.includeSensitiveWords;\n });\n }}\n >\n {(fmFormRenderProps) => {\n return (\n \n );\n }}\n \n );\n};\n\nconst RenderedFormChild = (props: {\n fmFormRenderProps: FmFormRenderProps;\n setToolbar: (element: JSX.Element) => void;\n templateName: string;\n}) => {\n const { fmFormRenderProps, templateName, setToolbar } = props;\n const formData = fmFormRenderProps.formData;\n const history = useHistory();\n useFormToolbar(() => {\n setToolbar(\n \n Settings: Sensitive Words\n \n \n );\n });\n\n return (\n \n Sensitive Words\n \n A list of sensitive words is built into this game, along with a\n dictionary. Unless you include sensitive words, these sensitive words\n will not be found when you find words.\n \n Regardless of this setting, it is YOUR responsibility to determine\n which words are appropriate for your games.\n \n Even if this setting is off, any word in your extra words list will\n still be found. And you may enter sensitive words manually when creating\n games.\n \n We may modify the list of sensitive words at any time. Our intention\n is to try to add words that are overtly obscene, sexist, or racist.\n Generally, words that have meanings which are both sensitive and not\n sensitive are NOT placed on the sensitive words list.\n \n \n \n \n );\n};\n","import List from \"@material-ui/core/List\";\nimport ListItem from \"@material-ui/core/ListItem\";\nimport ListItemIcon from \"@material-ui/core/ListItemIcon\";\nimport ListItemText from \"@material-ui/core/ListItemText\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Toolbar from \"@material-ui/core/Toolbar\";\nimport SensitiveIcon from \"@material-ui/icons/Block\";\nimport AdditionalWordsIcon from \"@material-ui/icons/PostAdd\";\nimport SettingsIcon from \"@material-ui/icons/Settings\";\nimport HiddenIcon from \"@material-ui/icons/VisibilityOff\";\nimport * as React from \"react\";\nimport { useContext, useEffect, useState } from \"react\";\nimport { Route, Switch, useHistory, useRouteMatch } from \"react-router-dom\";\nimport { DialogManagerContext } from \"../../../components/dialogTools/DialogManager\";\nimport { ExtraWordsPage } from \"./ExtraWordsPage\";\nimport { HiddenWordsPage } from \"./HiddenWordsPage\";\nimport { SensitiveWordsPage } from \"./SensitiveWordsPage\";\nimport { TopicFrame } from \"./TopicFrame\";\n\nconst drawerWidth = 240;\nconst useStyles = makeStyles((theme: Theme) => {\n const c = createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n appBar: {\n zIndex: theme.zIndex.drawer + 1,\n },\n drawer: {\n width: drawerWidth,\n flexShrink: 0,\n },\n drawerPaper: {\n width: drawerWidth,\n // position: \"static\",\n },\n drawerContainer: {\n overflow: \"auto\",\n },\n content: {\n flexGrow: 1,\n padding: theme.spacing(3),\n },\n nested: {\n paddingLeft: theme.spacing(4),\n },\n // Loads information about the app bar, including app bar height\n toolbar: theme.mixins.toolbar,\n });\n return c;\n});\n\nenum Page {\n Hidden,\n Extra,\n Sensitive,\n}\n\nexport interface SettingsTopicProps {}\n\nexport const SettingsTopic: React.FunctionComponent = (\n props\n) => {\n const classes = useStyles();\n const dialogMethods = useContext(DialogManagerContext);\n const [extraWordsToolbar, setExtraWordsToolbar] = useState(null);\n const [hiddenWordsToolbar, setHiddenWordsToolbar] = useState(\n null\n );\n const [sensitiveWordsToolbar, setSensitiveWordsToolbar] = useState<\n JSX.Element\n >(null);\n const [templatesToolbar, setTemplatesToolbar] = useState(null);\n const history = useHistory();\n let { path } = useRouteMatch();\n\n const leftNav = (\n \n history.push(`${path}/hidden`)}>\n \n \n \n \n \n history.push(`${path}/extra`)}>\n \n \n \n \n \n history.push(`${path}/sensitive`)}>\n \n \n \n \n \n \n );\n\n const [page, setPage] = useState(Page.Hidden);\n\n useEffect(() => {\n switch (history.location.pathname) {\n case `${path}/hidden`:\n case `${path}`:\n setPage(Page.Hidden);\n break;\n case `${path}/extra`:\n setPage(Page.Extra);\n break;\n case `${path}/sensitive`:\n setPage(Page.Sensitive);\n break;\n default:\n setPage(Page.Hidden);\n break;\n }\n }, [history.location.pathname]);\n return (\n <>\n {\n history.push(`${path}/hidden`);\n }}\n >\n \n \n }\n appIconMenuText=\"Settings\"\n leftNav={leftNav}\n toolbar={\n page === Page.Hidden ? (\n {hiddenWordsToolbar}\n ) : page === Page.Extra ? (\n {extraWordsToolbar}\n ) : page === Page.Sensitive ? (\n {sensitiveWordsToolbar}\n ) : (\n hiddenWordsToolbar\n )\n }\n >\n \n {\n return (\n <>\n \n \n );\n }}\n />\n {\n return ;\n }}\n />\n {\n return ;\n }}\n />\n {\n return (\n \n );\n }}\n />\n \n \n \n );\n};\n","import { createStyles, makeStyles } from \"@material-ui/core/styles\";\nimport { format } from \"date-fns\";\nimport * as React from \"react\";\nimport { useContext } from \"react\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingHeader from \"../../../components/SettingHeader\";\nimport Title from \"../../../components/Title\";\nimport { FmForm } from \"../../../formManager/FmForm\";\nimport { getSubscription } from \"../requests/getSubscription\";\nimport { UserContext } from \"./RouterTop\";\n\nconst useStyles = makeStyles(() =>\n createStyles({\n root: {\n display: \"flex\",\n flexWrap: \"wrap\",\n },\n textField: {\n width: \"40ch\",\n },\n })\n);\n\ninterface FormData {\n fmFormDataVersion: number; // required by FmForm\n expiry: Date;\n}\n\nexport interface SubscriptionProps {}\n\nexport const Subscription = () => {\n const authUserInfo = useContext(UserContext);\n return (\n {\n const s = await getSubscription({});\n return {\n expiry: s.expiry,\n fmFormDataVersion: 0,\n };\n },\n }}\n onSubmit={() => Promise.resolve()}\n >\n {(fmProps) => (\n \n Subscription for {authUserInfo.email}\n Expiration Date\n \n This is the last date on which you can use Cortex Author.\n \n {fmProps.formData.expiry\n ? format(fmProps.formData.expiry, \"P\")\n : \"Your subscription has no expiration date.\"}\n \n )}\n \n );\n};\n","import { makeRequestWithAuthentication } from \"../../../http/authenticated\";\nimport { ApiRequest, ApiResponse } from \"../../../domain/serverContract\";\n\nexport interface GetSubscriptionRequest extends ApiRequest {}\n\nexport interface GetSubscriptionResponse extends ApiResponse {\n expiry: Date; // undefined if no expiration date\n}\nexport async function getSubscription(\n request: GetSubscriptionRequest\n): Promise {\n return makeRequestWithAuthentication(\n request,\n \"/api/get_subscription\"\n );\n}\n","import * as React from \"react\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport Title from \"../../../components/Title\";\n\nexport const Terms = () => {\n return (\n \n Terms\n \n These terms describes what you can expect from us (Cortex Play) and what\n we expect from you regarding use of Cortex Author (\"the App\"). It is\n effective as of 13 August 2020. Questions about this policy should be\n emailed to terms @ cortexplay.com.\n
      \n
    • \n What you can expect from us:\n
        \n
      • \n the App should help you design games that are enjoyable and\n interesting\n
      • \n
      • the App should have good performance and availability
      • \n
      • \n we will not share your personal information outside of Cortex\n Play\n
      • \n
      \n
    • \n
    • \n What we expect from you:\n
        \n
      • not to allow other people to use your account.
      • \n
      • \n not to publish your games for commercial purposes. You may not\n charge for your games.\n
      • \n
      • \n to create a strong password that would be nearly impossible to\n guess.\n
      • \n
      • \n not to create games that are offensive in the context in which\n you are sharing them. The App allows you to choose which words\n are used in game play, and in game titles, descriptions, and\n elsewhere. While the App includes some tools to help you avoid\n creating offensive games, these tools offer little protection.\n Game content is entirely your responsibility.\n
      • \n
      • \n not to use the App for any purpose other than designing games.\n For example, you may not attempt to disrupt the App for other\n users by starting a denial of service attack on the App's web\n site.\n
      • \n
      • \n to share your games with your students, colleagues, friends, and\n family, but not with a public audience.\n
      • \n
      \n
    • \n
    \n
    \n
    \n );\n};\n","import IconButton from \"@material-ui/core/IconButton\";\nimport Tooltip from \"@material-ui/core/Tooltip\";\nimport MenuIcon from \"@material-ui/icons/Menu\";\nimport * as React from \"react\";\n\ninterface MainNavigationMenuIconProps {\n onClick?: () => void;\n edge?: \"start\" | \"end\" | false;\n}\n\nexport const MainNavigationMenuIcon: React.FunctionComponent = (\n props\n) => {\n return (\n \n \n \n \n \n );\n};\n","import { Divider } from \"@material-ui/core\";\nimport Avatar from \"@material-ui/core/Avatar\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { SubtleButton } from \"../../../components/buttons\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport {\n Dialog,\n getDialogMethods,\n makeDialog,\n} from \"../../../components/dialogTools/DialogManager\";\nimport { InfoDialogBase } from \"../../../components/dialogTools/InfoDialog\";\nimport { PageContainer } from \"../../../components/PageContainer\";\nimport { useUserProfile } from \"../requests/manageUserProfile\";\nimport { AuthUserInfo } from \"./RouterTop\";\n\nexport interface UserInfoDialogProps {\n authUserInfo: AuthUserInfo;\n}\n\nexport let userInfoDialogInternal: Dialog;\n\nexport const openUserInfoDialog = (props: UserInfoDialogProps) => {\n if (!userInfoDialogInternal) {\n userInfoDialogInternal = makeUserInfoDialog();\n }\n return getDialogMethods().open(userInfoDialogInternal, props);\n};\n\nexport const makeUserInfoDialog = () => {\n return makeDialog({\n componentRenderer: (dialogRenderProps) => {\n const history = useHistory();\n const userProfileData = useUserProfile();\n return (\n \n \n \n \n {userProfileData.initials}\n \n
    {dialogRenderProps.props.authUserInfo.email}
    \n
    {userProfileData.displayName}
    \n
    {userProfileData.initials}
    \n
    \n \n \n {\n history.push(\"/profile\");\n dialogRenderProps.close(true, undefined);\n }}\n >\n Edit Profile\n \n {\n history.push(\"/changeemail\");\n dialogRenderProps.close(true, undefined);\n }}\n >\n Change email\n \n {\n history.push(\"/changepassword\");\n dialogRenderProps.close(true, undefined);\n }}\n >\n Change password\n \n {\n history.push(\"/logoff\");\n dialogRenderProps.close(true, undefined);\n }}\n >\n Logoff\n \n {\" \"}\n
    \n
    \n );\n },\n });\n};\n","import Box from \"@material-ui/core/Box\";\nimport Grid from \"@material-ui/core/Grid\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { getVersion } from \"../app/author/requests/getVersion\";\nimport { InfoDialogBase } from \"./dialogTools/InfoDialog\";\nimport { openJustOkDialog } from \"./JustOkDialog\";\n\nexport interface VersionProps {}\n\nconst Version = (props: VersionProps) => {\n const [versionItems, setVersionItems] = useState([\"\"]);\n\n useEffect(() => {\n getVersion({})\n .then((reponse) => setVersionItems(reponse.versionItems))\n .catch((reason) => {\n throw new Error(\"Failed to get version: \" + reason);\n });\n }, []);\n\n return (\n \n \n {versionItems.map((item, index) => {\n return {item};\n })}\n \n \n );\n};\n\nexport const openVersionDialog = () => {\n openJustOkDialog({ content: , title: \"Version\" });\n};\n","import { ApiResponseHeader } from \"../../../domain/serverContract\";\nimport { makeRequest } from \"../../../http/http\";\n\nexport interface GetVersionRequest {}\n\nexport interface GetVersionResponse extends ApiResponseHeader {\n versionItems: string[];\n}\n\nexport async function getVersion(\n request: GetVersionRequest\n): Promise {\n return makeRequest(request, \"/api/get_version\");\n}\n","import AppBar from \"@material-ui/core/AppBar\";\nimport Avatar from \"@material-ui/core/Avatar\";\nimport Button from \"@material-ui/core/Button\";\nimport ClickAwayListener from \"@material-ui/core/ClickAwayListener\";\nimport Divider from \"@material-ui/core/Divider\";\nimport Drawer from \"@material-ui/core/Drawer\";\nimport List from \"@material-ui/core/List\";\nimport ListItem from \"@material-ui/core/ListItem\";\nimport ListItemIcon from \"@material-ui/core/ListItemIcon\";\nimport ListItemText from \"@material-ui/core/ListItemText\";\nimport { createStyles, makeStyles, Theme } from \"@material-ui/core/styles\";\nimport Toolbar from \"@material-ui/core/Toolbar\";\nimport Typography from \"@material-ui/core/Typography\";\nimport HomeIcon from \"@material-ui/icons/Home\";\nimport GamesIcon from \"@material-ui/icons/List\";\nimport SubscriptionIcon from \"@material-ui/icons/MonetizationOn\";\nimport ProfileIcon from \"@material-ui/icons/Person\";\nimport SettingsIcon from \"@material-ui/icons/Settings\";\nimport { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { useContext, useState } from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { useFreshState } from \"../../../hooks/useFreshState\";\nimport { useUserProfile } from \"../requests/manageUserProfile\";\nimport { SubtleButton } from \"../../../components/buttons\";\nimport { DialogManagerContext } from \"../../../components/dialogTools/DialogManager\";\nimport { openHelpDialog } from \"../../../components/HelpDialog\";\nimport Hider from \"../../../components/Hider\";\nimport { MainNavigationMenuIcon } from \"../../../components/MainNavigationMenuIcon\";\nimport { UserContext } from \"./RouterTop\";\nimport { openUserInfoDialog } from \"./UserInfoDialog\";\nimport { openVersionDialog } from \"../../../components/VersionDialog\";\n\nexport interface TopAppBarProps {\n setToggleNavMenu: (f: () => void) => void;\n isAdmin: boolean;\n}\nconst drawerWidth = 240;\nconst useStyles = makeStyles((theme: Theme) => {\n return createStyles({\n title: {\n flexGrow: 1,\n },\n menuButton: {\n marginRight: theme.spacing(2),\n },\n appBar: {\n zIndex: theme.zIndex.drawer + 10,\n },\n drawer: {\n width: drawerWidth,\n flexShrink: 0,\n zIndex: theme.zIndex.drawer + 9,\n },\n drawerPaper: {\n width: drawerWidth,\n zIndex: theme.zIndex.drawer + 9,\n // position: \"static\",\n },\n drawerContainer: {\n overflow: \"auto\",\n },\n content: {\n flexGrow: 1,\n padding: theme.spacing(3),\n },\n nested: {\n paddingLeft: theme.spacing(4),\n },\n // Loads information about the app bar, including app bar height\n toolbar: theme.mixins.toolbar,\n });\n});\n\nexport const TopAppBar: React.FunctionComponent = (props) => {\n const [getOpenDrawer, setOpenDrawer] = useFreshState(() => false);\n const [ignoreExternalClickOnce, setIgnoreExternalClickOnce] = useState(false);\n const classes = useStyles();\n const toggleDrawer = () => {\n if (getOpenDrawer() === false) {\n setIgnoreExternalClickOnce(true);\n setOpenDrawer(true);\n }\n };\n\n useState(() => props.setToggleNavMenu(toggleDrawer));\n const authUserInfo = useContext(UserContext);\n const history = useHistory();\n const dialogMethods = useContext(DialogManagerContext);\n const up = useUserProfile();\n const initials = up.initials;\n return (\n <>\n \n \n \n \n history.push(\"/home\")}\n style={{ cursor: \"pointer\" }}\n >\n Cortex Author\n \n \n openHelpDialog({})}>\n Help\n \n {firebaseauth().currentUser ? (\n openUserInfoDialog({ authUserInfo })}\n >\n {initials}\n \n ) : (\n history.push(\"/login\")}\n >\n Login\n \n )}\n \n \n {\n if (getOpenDrawer() === false) return;\n if (ignoreExternalClickOnce) {\n setIgnoreExternalClickOnce(false);\n } else {\n setOpenDrawer(false);\n }\n }}\n >\n \n \n setOpenDrawer(false)}\n onKeyDown={() => setOpenDrawer(false)}\n >\n \n {\n history.push(\"/home\");\n }}\n >\n \n \n \n \n \n {\n history.push(\"/games\");\n }}\n >\n \n \n \n \n \n {\n history.push(\"/settings\");\n }}\n >\n \n \n \n \n \n \n \n \n history.push(\"/subscription\")}>\n \n \n \n \n \n history.push(\"/profile\")}>\n \n \n \n \n \n {\n openVersionDialog();\n }}\n >\n \n \n \n \n history.push(\"/privacy\")}>\n \n \n history.push(\"/terms\")}>\n \n \n \n \n \n \n \n
    \n \n );\n};\n","import Card from \"@material-ui/core/Card\";\nimport CardActions from \"@material-ui/core/CardActions\";\nimport CardContent from \"@material-ui/core/CardContent\";\nimport CardHeader from \"@material-ui/core/CardHeader\";\nimport CardMedia from \"@material-ui/core/CardMedia\";\nimport { red } from \"@material-ui/core/colors\";\nimport Divider from \"@material-ui/core/Divider\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nimport { StrongGuidingButton } from \"../../../components/buttons\";\nimport { ComputeIcon } from \"../../../components/icons/ComputeIcon\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { openAddGameDialog } from \"./AddGameDialog\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n maxWidth: 345,\n minHeight: 410,\n margin: \"1rem\",\n },\n header: {\n paddingBottom: 0,\n paddingTop: 0,\n },\n media: {\n height: \"100%\",\n backgroundSize: \"contain\",\n },\n avatar: {\n backgroundColor: red[500],\n },\n}));\n\nexport function HomeComputeCard() {\n const classes = useStyles();\n return (\n \n \n openAddGameDialog({ title: \"Create Compute Game\", gameType: \"c\" })\n }\n >\n \n \n }\n title=\"Create Compute Games\"\n subheader=\"Add, subtract, multiply, and/or divide.\"\n />\n \n \n \n openAddGameDialog({ title: \"Create Compute Game\", gameType: \"c\" })\n }\n >\n Create Compute Game\n \n \n \n \n openAddGameDialog({ title: \"Create Compute Game\", gameType: \"c\" })\n }\n >\n \n
    \n \n \n \n You choose the operations (+, -, ×, ÷), the operands (e.g., 1-10), the\n time limit (if any), and the number of challenges.\n \n \n \n );\n}\n","import Card from \"@material-ui/core/Card\";\nimport CardActions from \"@material-ui/core/CardActions\";\nimport CardContent from \"@material-ui/core/CardContent\";\nimport CardHeader from \"@material-ui/core/CardHeader\";\nimport { red } from \"@material-ui/core/colors\";\nimport Divider from \"@material-ui/core/Divider\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { MildGuidingButton } from \"../../../components/buttons\";\nimport { LibraryIcon } from \"../../../components/icons/LibraryIcon\";\nimport { RowContainer } from \"../../../components/RowContainer\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n maxWidth: 345,\n minHeight: 175,\n margin: \"1rem\",\n },\n header: {\n paddingBottom: 0,\n paddingTop: 0,\n },\n media: {\n height: \"100%\",\n backgroundSize: \"contain\",\n },\n avatar: {\n backgroundColor: red[500],\n },\n}));\n\nexport function HomeLibraryGamesCard() {\n const classes = useStyles();\n const history = useHistory();\n return (\n \n history.push(\"/games/library\")}\n >\n \n \n }\n title=\"Library Games\"\n />\n \n \n history.push(\"/games/library\")}>\n See Library Games\n \n \n \n \n \n \n The library has many games available for you to quickly import,\n customize, and use.\n \n \n \n );\n}\n","import Card from \"@material-ui/core/Card\";\nimport CardActions from \"@material-ui/core/CardActions\";\nimport CardContent from \"@material-ui/core/CardContent\";\nimport CardHeader from \"@material-ui/core/CardHeader\";\nimport CardMedia from \"@material-ui/core/CardMedia\";\nimport { red } from \"@material-ui/core/colors\";\nimport Divider from \"@material-ui/core/Divider\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport SpellIcon from \"@material-ui/icons/FontDownload\";\nimport * as React from \"react\";\nimport { StrongGuidingButton } from \"../../../components/buttons\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { openAddGameDialog } from \"./AddGameDialog\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n maxWidth: 345,\n minHeight: 410,\n margin: \"1rem\",\n },\n header: {\n paddingBottom: 0,\n paddingTop: 0,\n },\n media: {\n height: \"100%\",\n backgroundSize: \"contain\",\n },\n avatar: {\n backgroundColor: red[500],\n },\n}));\n\nexport function HomeSpellCard() {\n const classes = useStyles();\n\n return (\n \n \n openAddGameDialog({ title: \"Create Spell Game\", gameType: \"s\" })\n }\n >\n \n \n }\n title=\"Create Spell Games\"\n subheader=\"Spell many words from one set of scrambled letters.\"\n />\n \n \n \n openAddGameDialog({ title: \"Create Spell Game\", gameType: \"s\" })\n }\n >\n Create Spell Game\n \n \n \n \n openAddGameDialog({ title: \"Create Spell Game\", gameType: \"s\" })\n }\n >\n \n \n \n \n \n You choose the letters and the words, and determine how the game is\n scored.\n \n \n \n );\n}\n","import Card from \"@material-ui/core/Card\";\nimport CardActions from \"@material-ui/core/CardActions\";\nimport CardContent from \"@material-ui/core/CardContent\";\nimport CardHeader from \"@material-ui/core/CardHeader\";\nimport CardMedia from \"@material-ui/core/CardMedia\";\nimport { red } from \"@material-ui/core/colors\";\nimport Divider from \"@material-ui/core/Divider\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nimport { StrongGuidingButton } from \"../../../components/buttons\";\nimport { TwistIcon } from \"../../../components/icons/TwistIcon\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport { openAddGameDialog } from \"./AddGameDialog\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n maxWidth: 345,\n minHeight: 410,\n margin: \"1rem\",\n },\n header: {\n paddingBottom: 0,\n paddingTop: 0,\n },\n media: {\n height: \"100%\",\n backgroundSize: \"contain\",\n },\n avatar: {\n backgroundColor: red[500],\n },\n}));\n\nexport function HomeTwistCard() {\n const classes = useStyles();\n return (\n \n \n openAddGameDialog({ title: \"Create Twist Game\", gameType: \"t\" })\n }\n >\n \n \n }\n title=\"Create Twist Games\"\n subheader=\"Solve spelling challenges with a twist.\"\n />\n \n \n \n openAddGameDialog({ title: \"Create Twist Game\", gameType: \"t\" })\n }\n >\n Create Twist Game\n \n \n \n \n openAddGameDialog({ title: \"Create Twist Game\", gameType: \"t\" })\n }\n >\n \n \n \n \n \n You choose the solutions, the scrambled and pre-filled letters for\n each solution, and determine how the game is scored.\n \n \n \n );\n}\n","import Card from \"@material-ui/core/Card\";\nimport CardActions from \"@material-ui/core/CardActions\";\nimport CardContent from \"@material-ui/core/CardContent\";\nimport CardHeader from \"@material-ui/core/CardHeader\";\nimport { red } from \"@material-ui/core/colors\";\nimport Divider from \"@material-ui/core/Divider\";\nimport IconButton from \"@material-ui/core/IconButton\";\nimport { makeStyles } from \"@material-ui/core/styles\";\nimport Typography from \"@material-ui/core/Typography\";\nimport * as React from \"react\";\nimport { useHistory } from \"react-router-dom\";\nimport { MildGuidingButton } from \"../../../components/buttons\";\nimport { GamesIcon } from \"../../../components/icons/GamesIcon\";\nimport { RowContainer } from \"../../../components/RowContainer\";\n\nconst useStyles = makeStyles((theme) => ({\n root: {\n maxWidth: 345,\n minHeight: 175,\n margin: \"1rem\",\n },\n header: {\n paddingBottom: 0,\n paddingTop: 0,\n },\n media: {\n height: \"100%\",\n backgroundSize: \"contain\",\n },\n avatar: {\n backgroundColor: red[500],\n },\n}));\n\nexport function HomeYourGamesCard() {\n const classes = useStyles();\n const history = useHistory();\n return (\n \n history.push(\"/games\")}>\n \n \n }\n title=\"Your Games\"\n />\n \n \n history.push(\"/games\")}>\n See Your Games\n \n \n \n \n \n \n View, modify, and publish your games. You can also import games from\n other authors.\n \n \n \n );\n}\n","import * as React from \"react\";\nimport { ColumnContainer } from \"../../../components/ColumnContainer\";\nimport Emphasize from \"../../../components/Emphasize\";\nimport { useHelp } from \"../../../components/HelpDialog\";\nimport { MainNavigationMenuIcon } from \"../../../components/MainNavigationMenuIcon\";\nimport { RowContainer } from \"../../../components/RowContainer\";\nimport SettingDescription from \"../../../components/SettingDescription\";\nimport SettingHeader from \"../../../components/SettingHeader\";\nimport SettingsContainer from \"../../../components/SettingsContainer\";\nimport { Title } from \"../../../components/Title\";\nimport { CreateGameButton } from \"./CreateGameButton\";\nimport { HomeComputeCard } from \"./HomeComputeCard\";\nimport { HomeLibraryGamesCard } from \"./HomeLibraryGamesCard\";\nimport { HomeSpellCard } from \"./HomeSpellCard\";\nimport { HomeTwistCard } from \"./HomeTwistCard\";\nimport { HomeYourGamesCard } from \"./HomeYourGamesCard\";\n\ninterface HomeProps {\n getToggleNavMenu: () => () => void;\n}\nexport const Home = (props: HomeProps) => {\n useHelp(\"Home\", , true);\n return (\n \n Game Authoring Dashboard\n \n \n \n \n \n \n \n \n );\n};\n\nconst MyHelp = () => {\n return (\n \n Create a New Game\n \n Go to the game app for the game you want to create, and click\n \n at the top. To go to a game app, open the navigation menu\n \n and click on the app name (for example, Spell).\n \n See Your Games\n \n Open the navigation menu\n \n and click on the app name (for example, Spell).\n \n Open the Navigation Menu\n \n Click\n \n to open and close the navigation menu on the left.\n \n Create a Template Game\n \n Each time you create a game, the new game will be a copy of your\n template game. To create a template, click the{\" \"}\n Make This Game My Template button when you are\n editing your game.\n \n \n );\n};\n","import { auth as firebaseauth } from \"firebase/app\";\nimport \"firebase/auth\";\nimport * as React from \"react\";\nimport { createContext, useEffect, useRef, useState } from \"react\";\nimport { Route, Switch } from \"react-router-dom\";\nimport { AdminTopic } from \"../admin/components/AdminTopic\";\nimport { ChangeEmail } from \"./ChangeEmail\";\nimport { ChangePassword } from \"./ChangePassword\";\nimport { CompleteRegistration } from \"./CompleteRegistration\";\nimport { GamesTopic } from \"./GamesTopic\";\nimport { Login } from \"./Login\";\nimport { Logoff } from \"./Logoff\";\nimport { Privacy } from \"./Privacy\";\nimport { Profile } from \"./Profile\";\nimport { Register, RegistrationSubmitted } from \"./Register\";\nimport { SettingsTopic } from \"./SettingsTopic\";\nimport { Subscription } from \"./Subscription\";\nimport { Terms } from \"./Terms\";\nimport { TopAppBar } from \"./TopAppBar\";\nimport { Home } from \"./Home\";\n\n/*\nThe main nav is topics, such as the games (Spell, Compute, etc.), subscription management, and profile managemenent.\nWork is done on pages, such as SpellGamesPageComponent, which is the Games pages in the Spell topic.\nNavigation is ultimately to pages.\n\nNav is //.\n*/\n\nexport interface AuthUserInfo {\n email: string;\n displayName: string;\n}\n\nlet authUserInfo: AuthUserInfo;\n\nexport const UserContext = createContext({\n email: \"\",\n displayName: \"\",\n});\n\nlet lastAuthIdTokenRefresh = Date.now();\nlet authPromise: Promise;\n\nexport const getAuthIdToken = () => {\n const currentUser = firebaseauth().currentUser;\n if (!currentUser) {\n authPromise = undefined;\n return Promise.resolve(undefined);\n }\n const now = Date.now();\n // Refresh every 15m\n if (authPromise && now - lastAuthIdTokenRefresh < 15 * 60 * 1000) {\n return authPromise;\n }\n authPromise = currentUser\n .getIdToken(/* forceRefresh */ true)\n .then(function (authIdToken) {\n lastAuthIdTokenRefresh = now;\n return authIdToken;\n })\n .catch(function (error) {\n console.error(error);\n throw new Error(\"Failed to get Id token\");\n });\n return authPromise;\n};\n\nexport interface RouterTopProps {}\nexport const RouterTop = () => {\n const [uid, setUid] = useState(undefined);\n const [admin, setAdmin] = useState(undefined);\n const toggleNavMenu = useRef<() => void>(undefined);\n useEffect(() => {\n firebaseauth().onAuthStateChanged(function (user) {\n authUserInfo = {\n email: \"\",\n displayName: \"\",\n };\n if (user) {\n getAuthIdToken()\n .then(function () {\n authUserInfo = {\n email: firebaseauth().currentUser.email,\n displayName: firebaseauth().currentUser.displayName,\n };\n setUid(user.uid);\n })\n .then(async (r) => {\n const idTokenResult = await firebaseauth().currentUser.getIdTokenResult();\n const adminData = idTokenResult.claims[\"admin\"] as string;\n if (!adminData) {\n setAdmin(0);\n } else {\n setAdmin(parseInt(adminData));\n }\n return r;\n })\n .catch(function (error) {\n console.error(error);\n throw new Error(\"Failed to get Id token\");\n });\n } else {\n setUid(null);\n }\n });\n }, []);\n\n // If first time in return null. Otherwise if the user is already logged in we first see the login page flash.\n if (uid === undefined) return null;\n\n if (uid === null) {\n return (\n <>\n void) => {\n toggleNavMenu.current = f;\n }}\n />\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n );\n }\n // We check isAdmin. We don't want to force the user back to the home page until we figure out if they are an admin.\n if (admin === undefined) return null;\n return (\n \n 0}\n setToggleNavMenu={(f: () => void) => {\n toggleNavMenu.current = f;\n }}\n />\n \n \n toggleNavMenu.current} />\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {\n // Admin will boot anyone not an admin\n return ;\n }}\n />\n \n \n );\n};\n","import DateFnsUtils from \"@date-io/date-fns\";\r\nimport CssBaseline from \"@material-ui/core/CssBaseline\";\r\nimport { createMuiTheme, MuiThemeProvider } from \"@material-ui/core/styles\";\r\nimport { MuiPickersUtilsProvider } from \"@material-ui/pickers\";\r\nimport { initializeApp } from \"firebase/app\";\r\nimport { enableMapSet, enablePatches } from \"immer\";\r\nimport * as React from \"react\";\r\nimport * as ReactDOM from \"react-dom\";\r\nimport { BrowserRouter } from \"react-router-dom\";\r\nimport { DialogManager } from \"../../components/dialogTools/DialogManager\";\r\nimport { NotificationManager } from \"../../components/NotificationManager\";\r\nimport { RouterTop } from \"./components/RouterTop\";\r\n\r\nenableMapSet();\r\nconst logoBlue = \"#0055aa\";\r\nconst logoYellow = \"#FFCB05\";\r\nconst logoFontSize = 110;\r\nconst logoFontName = \"Assistant\";\r\n\r\nconst theme = createMuiTheme({\r\n palette: {\r\n primary: {\r\n // light: \"#fff\",\r\n main: \"#0055aa\",\r\n // dark: \"#000\",\r\n },\r\n secondary: {\r\n main: \"#FFCB05\",\r\n },\r\n },\r\n});\r\n\r\n// Initialize Identity Platform\r\n// CP_IDENTITY is defined in the start-up html file.\r\ndeclare var CP_IDENTITY: string;\r\nconst identityTokens = CP_IDENTITY.split(\",\");\r\nconst config = {\r\n apiKey: identityTokens[0],\r\n authDomain: identityTokens[1],\r\n};\r\n\r\ninitializeApp(config);\r\nenablePatches();\r\n\r\nReactDOM.render(\r\n <>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n ,\r\n document.getElementById(\"main\")\r\n);\r\n"],"sourceRoot":""}