]> Untitled Git - lemmy-ui.git/blob - src/shared/components/common/language-select.tsx
625379e26a4c6155299cb03949acb51b95f40e0d
[lemmy-ui.git] / src / shared / components / common / language-select.tsx
1 import { selectableLanguages } from "@utils/app";
2 import { randomStr } from "@utils/helpers";
3 import classNames from "classnames";
4 import { Component, linkEvent } from "inferno";
5 import { Language } from "lemmy-js-client";
6 import { i18n } from "../../i18next";
7 import { UserService } from "../../services/UserService";
8 import { Icon } from "./icon";
9
10 interface LanguageSelectProps {
11   allLanguages: Language[];
12   siteLanguages: number[];
13   selectedLanguageIds?: number[];
14   multiple?: boolean;
15   onChange(val: number[]): any;
16   showAll?: boolean;
17   showSite?: boolean;
18   iconVersion?: boolean;
19   disabled?: boolean;
20   showLanguageWarning?: boolean;
21 }
22
23 export class LanguageSelect extends Component<LanguageSelectProps, any> {
24   private id = `language-select-${randomStr()}`;
25
26   constructor(props: any, context: any) {
27     super(props, context);
28   }
29
30   componentDidMount() {
31     this.setSelectedValues();
32   }
33
34   // Necessary because there is no HTML way to set selected for multiple in value=
35   setSelectedValues() {
36     const ids = this.props.selectedLanguageIds?.map(toString);
37     if (ids) {
38       const select = (document.getElementById(this.id) as HTMLSelectElement)
39         .options;
40       for (let i = 0; i < select.length; i++) {
41         const o = select[i];
42         if (ids.includes(o.value)) {
43           o.selected = true;
44         }
45       }
46     }
47   }
48
49   render() {
50     return this.props.iconVersion ? (
51       this.selectBtn
52     ) : (
53       <div className="language-select">
54         {this.props.multiple && this.props.showLanguageWarning && (
55           <div className="alert alert-warning" role="alert">
56             {i18n.t("undetermined_language_warning")}
57           </div>
58         )}
59         <div className="mb-3 row">
60           <label
61             className={classNames(
62               "col-form-label",
63               `col-sm-${this.props.multiple ? 3 : 2}`
64             )}
65             htmlFor={this.id}
66           >
67             {i18n.t(this.props.multiple ? "language_plural" : "language")}
68           </label>
69           <div
70             className={classNames(`col-sm-${this.props.multiple ? 9 : 10}`, {
71               "input-group": this.props.multiple,
72             })}
73           >
74             {this.selectBtn}
75             {this.props.multiple && (
76               <button
77                 className="btn btn-outline-secondary"
78                 onClick={linkEvent(this, this.handleDeselectAll)}
79               >
80                 <Icon icon="x" />
81               </button>
82             )}
83           </div>
84         </div>
85       </div>
86     );
87   }
88
89   get selectBtn() {
90     const selectedLangs = this.props.selectedLanguageIds;
91     const filteredLangs = selectableLanguages(
92       this.props.allLanguages,
93       this.props.siteLanguages,
94       this.props.showAll,
95       this.props.showSite,
96       UserService.Instance.myUserInfo
97     );
98
99     return (
100       <select
101         className={classNames("form-select w-auto", {
102           "d-inline-block": !this.props.iconVersion,
103         })}
104         id={this.id}
105         onChange={linkEvent(this, this.handleLanguageChange)}
106         aria-label={i18n.t("language_select_placeholder")}
107         multiple={this.props.multiple}
108         disabled={this.props.disabled}
109       >
110         {!this.props.multiple && (
111           <option selected disabled hidden>
112             {i18n.t("language_select_placeholder")}
113           </option>
114         )}
115         {filteredLangs.map(l => (
116           <option
117             key={l.id}
118             value={l.id}
119             selected={selectedLangs?.includes(l.id)}
120           >
121             {l.name}
122           </option>
123         ))}
124       </select>
125     );
126   }
127
128   handleLanguageChange(i: LanguageSelect, event: any) {
129     const options: HTMLOptionElement[] = Array.from(event.target.options);
130     const selected: number[] = options
131       .filter(o => o.selected)
132       .map(o => Number(o.value));
133
134     i.props.onChange(selected);
135   }
136
137   handleDeselectAll(i: LanguageSelect, event: any) {
138     event.preventDefault();
139     i.props.onChange([]);
140   }
141 }