diff --git a/src/components/ProjectSettings/ProjectLanguages/ProjectLanguages.tsx b/src/components/ProjectSettings/ProjectLanguages/ProjectLanguages.tsx
index 9f6524f757..69e348784a 100644
--- a/src/components/ProjectSettings/ProjectLanguages/ProjectLanguages.tsx
+++ b/src/components/ProjectSettings/ProjectLanguages/ProjectLanguages.tsx
@@ -1,11 +1,10 @@
-import { Grid, Typography } from "@material-ui/core";
+import { Button, Grid, Tooltip, Typography } from "@material-ui/core";
+import { Add, ArrowUpward, Clear, Done } from "@material-ui/icons";
+import { LanguagePicker, languagePickerStrings_en } from "mui-language-picker";
import React from "react";
-import {
- LocalizeContextProps,
- Translate,
- withLocalize,
-} from "react-localize-redux";
+import { Translate } from "react-localize-redux";
+import { updateProject } from "../../../backend";
import { Project, WritingSystem } from "../../../types/project";
import theme from "../../../types/theme";
@@ -13,54 +12,184 @@ interface LanguageProps {
project: Project;
}
-class ProjectLanguages extends React.Component<
- LanguageProps & LocalizeContextProps
+interface LanguageState {
+ add: boolean;
+ name: string;
+ bcp47: string;
+ font: string;
+}
+
+export default class ProjectLanguages extends React.Component<
+ LanguageProps,
+ LanguageState
> {
- renderWritingSystem(ws: WritingSystem, index?: number) {
+ constructor(props: LanguageProps) {
+ super(props);
+ this.state = this.defaultState;
+ }
+
+ private defaultState: LanguageState = {
+ add: false,
+ name: "",
+ bcp47: "",
+ font: "",
+ };
+
+ setNewAnalysisDefault(index: number) {
+ const newDefault = this.props.project.analysisWritingSystems.splice(
+ index,
+ 1
+ )[0];
+ this.props.project.analysisWritingSystems.splice(0, 0, newDefault);
+ updateProject(this.props.project)
+ .then(() => this.resetState())
+ .catch((err) => console.error(err));
+ }
+
+ addAnalysisWritingSystem() {
+ const ws = {
+ name: this.state.name,
+ bcp47: this.state.bcp47,
+ font: this.state.font,
+ };
+ this.props.project.analysisWritingSystems.push(ws);
+ updateProject(this.props.project)
+ .then(() => this.resetState())
+ .catch((err) => console.error(err));
+ }
+
+ isNewWritingSystem() {
return (
-
-
- {index !== undefined && {`${index + 1}. `}}
-
-
- {": "}
- {ws.name} {", "}
-
-
-
- {": "}
- {ws.bcp47}
- {", "}
-
-
-
- {": "}
- {ws.font}
-
-
-
+ this.state.bcp47 &&
+ !this.props.project.analysisWritingSystems
+ .map((ws) => ws.bcp47)
+ .includes(this.state.bcp47)
);
}
+ resetState() {
+ this.setState(this.defaultState);
+ }
+
render() {
return (
{": "}
- {this.renderWritingSystem(this.props.project.vernacularWritingSystem)}
+
{": "}
{this.props.project.analysisWritingSystems.map(
- (writingSystem, index) =>
- this.renderWritingSystem(writingSystem, index)
+ (writingSystem, index) => (
+ }
+ iconAction={() => this.setNewAnalysisDefault(index)}
+ />
+ )
)}
+ {this.state.add ? (
+
+
+ this.setState({ bcp47 })}
+ name={this.state.bcp47}
+ setName={(name: string) => this.setState({ name })}
+ font={this.state.font}
+ setFont={(font: string) => this.setState({ font })}
+ t={languagePickerStrings_en}
+ />
+ {" "}
+
+
+ {" "}
+
+
+
+
+ ) : (
+
+ }
+ placement="right"
+ >
+
+
+ )}
);
}
}
-export default withLocalize(ProjectLanguages);
+function MakeDefaultButton() {
+ return (
+
+ }
+ placement="right"
+ >
+
+
+ );
+}
+
+interface ImmutableWritingSystemProps {
+ ws: WritingSystem;
+ index?: number;
+ icon?: any;
+ iconAction?: () => void;
+}
+
+export function ImmutableWritingSystem(props: ImmutableWritingSystemProps) {
+ return (
+
+ {props.index !== undefined && {`${props.index + 1}. `}}
+
+
+ {": "}
+ {props.ws.name} {", "}
+
+
+
+ {": "}
+ {props.ws.bcp47}
+ {", "}
+
+
+
+ {": "}
+ {props.ws.font}
+
+ {props.icon ? (
+
+
+
+ ) : null}
+
+ );
+}
diff --git a/src/components/ProjectSettings/ProjectLanguages/tests/ProjectLangauges.test.tsx b/src/components/ProjectSettings/ProjectLanguages/tests/ProjectLangauges.test.tsx
index 88fdc79a2e..2b8b071b20 100644
--- a/src/components/ProjectSettings/ProjectLanguages/tests/ProjectLangauges.test.tsx
+++ b/src/components/ProjectSettings/ProjectLanguages/tests/ProjectLangauges.test.tsx
@@ -1,29 +1,86 @@
+import { LanguagePicker } from "mui-language-picker";
import React from "react";
import { Provider } from "react-redux";
-import renderer from "react-test-renderer";
+import renderer, {
+ ReactTestInstance,
+ ReactTestRenderer,
+} from "react-test-renderer";
import configureMockStore from "redux-mock-store";
-import { defaultProject, Project } from "../../../../types/project";
+import {
+ defaultProject,
+ Project,
+ WritingSystem,
+} from "../../../../types/project";
import { defaultState } from "../../../App/DefaultState";
import ProjectLanguages from "../ProjectLanguages";
+jest.mock("../../../../backend", () => {
+ return { updateProject: (proj: Project) => mockUpdateProject(proj) };
+});
+
const createMockStore = configureMockStore([]);
const mockStore = createMockStore(defaultState);
-let mockProject: Project = {
- ...defaultProject,
- analysisWritingSystems: [
- { name: "a", bcp47: "a", font: "" },
- { name: "b", bcp47: "b", font: "" },
- ],
-};
-describe("Testing login component", () => {
- it("Renders without crashing", () => {
- renderer.act(() => {
- renderer.create(
-
-
-
- );
- });
+const mockAnalysisWritingSystems: WritingSystem[] = [
+ { name: "a", bcp47: "a", font: "" },
+ { name: "b", bcp47: "b", font: "" },
+];
+const mockUpdateProject = jest.fn((proj: Project) => {
+ return Promise.resolve(proj);
+});
+
+let projectMaster: ReactTestRenderer;
+let pickerHandle: ReactTestInstance;
+let buttonHandle: ReactTestInstance;
+
+function mockProject(systems?: WritingSystem[]) {
+ return { ...defaultProject, analysisWritingSystems: systems ?? [] };
+}
+
+function renderProjLangs(proj: Project) {
+ renderer.act(() => {
+ projectMaster = renderer.create(
+
+
+
+ );
+ });
+}
+
+function renderAndClickAdd() {
+ renderProjLangs(mockProject([...mockAnalysisWritingSystems]));
+ expect(projectMaster.root.findAllByType(LanguagePicker).length).toEqual(0);
+ projectMaster.root.findByProps({ id: "addNewLang" }).props.onClick();
+ expect(projectMaster.root.findAllByType(LanguagePicker).length).toEqual(1);
+}
+
+describe("ProjectLanguages", () => {
+ it("renders without crashing", () => {
+ renderProjLangs(mockProject([...mockAnalysisWritingSystems]));
+ });
+
+ it("can add language to project", () => {
+ renderAndClickAdd();
+ pickerHandle = projectMaster.root.findByType(LanguagePicker);
+ pickerHandle.props.setCode("z");
+ pickerHandle.props.setName("z");
+ projectMaster.root.findByProps({ id: "submitNewLang" }).props.onClick();
+ expect(mockUpdateProject).toBeCalledWith(
+ mockProject([
+ ...mockAnalysisWritingSystems,
+ { name: "z", bcp47: "z", font: "" },
+ ])
+ );
+ });
+
+ it("can only submit when new language selected", () => {
+ renderAndClickAdd();
+ pickerHandle = projectMaster.root.findByType(LanguagePicker);
+ buttonHandle = projectMaster.root.findByProps({ id: "submitNewLang" });
+ expect(buttonHandle.props.disabled).toBe(true);
+ pickerHandle.props.setCode(mockAnalysisWritingSystems[0].bcp47);
+ expect(buttonHandle.props.disabled).toBe(true);
+ pickerHandle.props.setCode("z");
+ expect(buttonHandle.props.disabled).toBe(false);
});
});
diff --git a/src/resources/translations.json b/src/resources/translations.json
index ad7645ac93..8df50a0896 100644
--- a/src/resources/translations.json
+++ b/src/resources/translations.json
@@ -295,7 +295,17 @@
],
"bcp47": ["BCP 47 Code", "BCP 47", "BCP 47"],
"name": ["Name", "Nombre", "Nom"],
- "font": ["Font", "Font", "Font"]
+ "font": ["Font", "Font", "Font"],
+ "addAnalysisLanguage": [
+ "Add an alternate analysis language.",
+ "Add an alternate analysis language.",
+ "Add an alternate analysis language."
+ ],
+ "makeDefaultAnalysisLanguage": [
+ "Make this the default analysis language.",
+ "Make this the default analysis language.",
+ "Make this the default analysis language."
+ ]
},
"name": ["Project Name", "Nombre del proyecto", "Nom du projet"],
"projectList": ["Projects", "Proyectos", "Projets"],