Skip to content

Commit

Permalink
Add user setting for turning gloss suggestion on/off (#3229)
Browse files Browse the repository at this point in the history
  • Loading branch information
imnasnainaec authored Aug 22, 2024
1 parent 32c0591 commit f90b698
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 9 deletions.
10 changes: 9 additions & 1 deletion Backend/Models/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,14 @@ public class User
[BsonElement("username")]
public string Username { get; set; }

/// <summary> Not implemented in frontend. </summary>
[BsonElement("uiLang")]
public string UILang { get; set; }

[Required]
[BsonElement("glossSuggestion")]
[BsonRepresentation(BsonType.String)]
public AutocompleteSetting GlossSuggestion { get; set; }

[Required]
[BsonElement("token")]
public string Token { get; set; }
Expand All @@ -94,6 +98,7 @@ public User()
Password = "";
Username = "";
UILang = "";
GlossSuggestion = AutocompleteSetting.On;
Token = "";
IsAdmin = false;
WorkedProjects = new();
Expand All @@ -115,6 +120,7 @@ public User Clone()
Password = Password,
Username = Username,
UILang = UILang,
GlossSuggestion = GlossSuggestion,
Token = Token,
IsAdmin = IsAdmin,
WorkedProjects = WorkedProjects.ToDictionary(kv => kv.Key, kv => kv.Value),
Expand All @@ -136,6 +142,7 @@ public bool ContentEquals(User other)
other.Password.Equals(Password, StringComparison.Ordinal) &&
other.Username.Equals(Username, StringComparison.Ordinal) &&
other.UILang.Equals(UILang, StringComparison.Ordinal) &&
other.GlossSuggestion.Equals(GlossSuggestion) &&
other.Token.Equals(Token, StringComparison.Ordinal) &&
other.IsAdmin == IsAdmin &&

Expand Down Expand Up @@ -172,6 +179,7 @@ public override int GetHashCode()
hash.Add(Password);
hash.Add(Username);
hash.Add(UILang);
hash.Add(GlossSuggestion);
hash.Add(Token);
hash.Add(IsAdmin);
return hash.ToHashCode();
Expand Down
3 changes: 2 additions & 1 deletion Backend/Repositories/UserRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ public async Task<ResultOfUpdate> Update(string userId, User user, bool updateIs
.Set(x => x.ProjectRoles, user.ProjectRoles)
.Set(x => x.Agreement, user.Agreement)
.Set(x => x.Username, user.Username)
.Set(x => x.UILang, user.UILang);
.Set(x => x.UILang, user.UILang)
.Set(x => x.GlossSuggestion, user.GlossSuggestion);

// If .Avatar or .Token has been set to null or "",
// this prevents it from being erased in the database
Expand Down
2 changes: 2 additions & 0 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
},
"userSettings": {
"contact": "Contact info",
"glossSuggestion": "Gloss spelling suggestions",
"glossSuggestionHint": "In Data Entry, give spelling suggestions for the Gloss being typed.",
"phone": "Phone number",
"uiLanguage": "User-interface language",
"uiLanguageDefault": "(Default to browser language)",
Expand Down
8 changes: 8 additions & 0 deletions src/api/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* Do not edit the class manually.
*/

import { AutocompleteSetting } from "./autocomplete-setting";

/**
*
* @export
Expand Down Expand Up @@ -108,4 +110,10 @@ export interface User {
* @memberof User
*/
isAdmin: boolean;
/**
*
* @type {AutocompleteSetting}
* @memberof User
*/
glossSuggestion: AutocompleteSetting;
}
8 changes: 6 additions & 2 deletions src/components/DataEntry/DataEntryTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
Word,
} from "api/models";
import * as backend from "backend";
import { getUserId } from "backend/localStorage";
import { getCurrentUser, getUserId } from "backend/localStorage";
import NewEntry from "components/DataEntry/DataEntryTable/NewEntry";
import RecentEntry from "components/DataEntry/DataEntryTable/RecentEntry";
import { filterWordsWithSenses } from "components/DataEntry/utilities";
Expand Down Expand Up @@ -271,7 +271,11 @@ export default function DataEntryTable(
const newVernInput = useRef<HTMLInputElement>(null);
const spellChecker = useContext(SpellCheckerContext);
useEffect(() => {
spellChecker.updateLang(analysisLang.bcp47);
spellChecker.updateLang(
getCurrentUser()?.glossSuggestion === AutocompleteSetting.Off
? undefined
: analysisLang.bcp47
);
}, [analysisLang.bcp47, spellChecker]);
const { t } = useTranslation();

Expand Down
3 changes: 3 additions & 0 deletions src/components/DataEntry/DataEntryTable/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
newSemanticDomainTreeNode,
semDomFromTreeNode,
} from "types/semanticDomain";
import { newUser } from "types/user";
import {
multiSenseWord,
newGloss,
Expand Down Expand Up @@ -53,6 +54,7 @@ jest.mock("backend", () => ({
updateWord: (...args: any[]) => mockUpdateWord(...args),
}));
jest.mock("backend/localStorage", () => ({
getCurrentUser: () => mockUser,
getUserId: () => mockUserId,
}));
jest.mock("components/DataEntry/DataEntryTable/NewEntry/SenseDialog");
Expand All @@ -78,6 +80,7 @@ const mockMultiWord = multiSenseWord("vern", ["gloss1", "gloss2"]);
const mockSemDomId = "semDomId";
const mockTreeNode = newSemanticDomainTreeNode(mockSemDomId);
const mockSemDom = semDomFromTreeNode(mockTreeNode);
const mockUser = newUser();
const mockUserId = "mockUserId";
const mockStore = configureMockStore()(defaultState);

Expand Down
2 changes: 1 addition & 1 deletion src/components/ProjectSettings/ProjectAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function ProjectAutocomplete(
title={t("projectSettings.autocomplete.hint")}
placement={document.body.dir === "rtl" ? "left" : "right"}
>
<HelpOutline />
<HelpOutline fontSize="small" />
</Tooltip>
</Grid>
</Grid>
Expand Down
49 changes: 46 additions & 3 deletions src/components/UserSettings/UserSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Email, Phone } from "@mui/icons-material";
import { Email, HelpOutline, Phone } from "@mui/icons-material";
import {
Button,
Card,
Expand All @@ -7,13 +7,14 @@ import {
MenuItem,
Select,
TextField,
Tooltip,
Typography,
} from "@mui/material";
import { enqueueSnackbar } from "notistack";
import { FormEvent, Fragment, ReactElement, useState } from "react";
import { useTranslation } from "react-i18next";

import { User } from "api/models";
import { AutocompleteSetting, User } from "api/models";
import { isEmailTaken, updateUser } from "backend";
import { getAvatar, getCurrentUser } from "backend/localStorage";
import { asyncLoadSemanticDomains } from "components/Project/ProjectActions";
Expand All @@ -34,6 +35,7 @@ export enum UserSettingsIds {
FieldName = "user-settings-name",
FieldPhone = "user-settings-phone",
FieldUsername = "user-settings-username",
SelectGlossSuggestion = "user-settings-gloss-suggestion",
SelectUiLang = "user-settings-ui-lang",
}

Expand All @@ -57,6 +59,9 @@ export function UserSettings(props: {
const [phone, setPhone] = useState(props.user.phone);
const [email, setEmail] = useState(props.user.email);
const [uiLang, setUiLang] = useState(props.user.uiLang ?? "");
const [glossSuggestion, setGlossSuggestion] = useState(
props.user.glossSuggestion
);
const [emailTaken, setEmailTaken] = useState(false);
const [avatar, setAvatar] = useState(getAvatar());

Expand All @@ -72,7 +77,8 @@ export function UserSettings(props: {
name === props.user.name &&
phone === props.user.phone &&
punycode.toUnicode(email) === props.user.email &&
uiLang === (props.user.uiLang ?? "");
uiLang === (props.user.uiLang ?? "") &&
glossSuggestion === props.user.glossSuggestion;

async function onSubmit(e: FormEvent<HTMLFormElement>): Promise<void> {
e.preventDefault();
Expand All @@ -83,6 +89,7 @@ export function UserSettings(props: {
phone,
email: punycode.toUnicode(email),
uiLang,
glossSuggestion,
hasAvatar: !!avatar,
});

Expand Down Expand Up @@ -226,6 +233,42 @@ export function UserSettings(props: {
</Grid>
</Grid>

<Grid item container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">
{t("userSettings.glossSuggestion")}
</Typography>
</Grid>

<Grid item>
<Select
data-testid={UserSettingsIds.SelectGlossSuggestion}
id={UserSettingsIds.SelectGlossSuggestion}
onChange={(e) =>
setGlossSuggestion(e.target.value as AutocompleteSetting)
}
value={glossSuggestion}
variant="standard"
>
<MenuItem value={AutocompleteSetting.Off}>
{t("projectSettings.autocomplete.off")}
</MenuItem>
<MenuItem value={AutocompleteSetting.On}>
{t("projectSettings.autocomplete.on")}
</MenuItem>
</Select>
</Grid>

<Grid item>
<Tooltip
title={t("userSettings.glossSuggestionHint")}
placement={document.body.dir === "rtl" ? "left" : "right"}
>
<HelpOutline fontSize="small" />
</Tooltip>
</Grid>
</Grid>

<Grid item container justifyContent="flex-end">
<Button
data-testid={UserSettingsIds.ButtonSubmit}
Expand Down
3 changes: 2 additions & 1 deletion src/types/user.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { User } from "api/models";
import { AutocompleteSetting, User } from "api/models";

export function newUser(name = "", username = "", password = ""): User {
return {
Expand All @@ -12,6 +12,7 @@ export function newUser(name = "", username = "", password = ""): User {
phone: "",
projectRoles: {},
workedProjects: {},
glossSuggestion: AutocompleteSetting.On,
token: "",
isAdmin: false,
};
Expand Down
2 changes: 2 additions & 0 deletions src/utilities/spellChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export default class SpellChecker {
async updateLang(lang?: string): Promise<void> {
if (!lang) {
this.bcp47 = undefined;
this.dictLoaded = {};
this.spell = undefined;
return;
}
const bcp47 = lang.split("-")[0] as Bcp47Code;
Expand Down

0 comments on commit f90b698

Please sign in to comment.