Hide create community (#787)

* Adding post and comment language tagging. Fixes #771

* Hiding create community button. Fixes #754
This commit is contained in:
Dessalines 2022-09-22 11:14:58 -04:00 committed by GitHub
parent 6320357d21
commit c6e3a4213a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 321 additions and 36 deletions

@ -1 +1 @@
Subproject commit 7ac48ae98271b3b573e28c90b87f9704492e0b62 Subproject commit 05fb028e8b85de9e7e9d516abb1ebb8a01aad060

View file

@ -78,7 +78,7 @@
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.1", "husky": "^8.0.1",
"import-sort-style-module": "^6.0.0", "import-sort-style-module": "^6.0.0",
"lemmy-js-client": "0.17.0-rc.43", "lemmy-js-client": "0.17.0-rc.44",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"mini-css-extract-plugin": "^2.6.1", "mini-css-extract-plugin": "^2.6.1",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",

View file

@ -21,6 +21,7 @@ import { UserService, WebSocketService } from "../../services";
import { import {
amAdmin, amAdmin,
auth, auth,
canCreateCommunity,
donateLemmyUrl, donateLemmyUrl,
isBrowser, isBrowser,
notifyComment, notifyComment,
@ -274,7 +275,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
{i18n.t("create_post")} {i18n.t("create_post")}
</NavLink> </NavLink>
</li> </li>
{this.canCreateCommunity && ( {canCreateCommunity(this.props.siteRes) && (
<li className="nav-item"> <li className="nav-item">
<NavLink <NavLink
to="/create_community" to="/create_community"
@ -528,13 +529,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
return amAdmin(Some(this.props.siteRes.admins)); return amAdmin(Some(this.props.siteRes.admins));
} }
get canCreateCommunity(): boolean {
let adminOnly = this.props.siteRes.site_view
.map(s => s.site.community_creation_admin_only)
.unwrapOr(false);
return !adminOnly || this.amAdmin;
}
handleToggleExpandNavbar(i: Navbar) { handleToggleExpandNavbar(i: Navbar) {
i.setState({ expanded: !i.state.expanded }); i.setState({ expanded: !i.state.expanded });
} }

View file

@ -7,6 +7,7 @@ import {
CommentResponse, CommentResponse,
CreateComment, CreateComment,
EditComment, EditComment,
Language,
UserOperation, UserOperation,
wsJsonToRes, wsJsonToRes,
wsUserOp, wsUserOp,
@ -17,6 +18,7 @@ import { UserService, WebSocketService } from "../../services";
import { import {
auth, auth,
capitalizeFirstLetter, capitalizeFirstLetter,
myFirstDiscussionLanguageId,
wsClient, wsClient,
wsSubscribe, wsSubscribe,
} from "../../utils"; } from "../../utils";
@ -32,6 +34,7 @@ interface CommentFormProps {
disabled?: boolean; disabled?: boolean;
focus?: boolean; focus?: boolean;
onReplyCancel?(): any; onReplyCancel?(): any;
allLanguages: Language[];
} }
interface CommentFormState { interface CommentFormState {
@ -74,11 +77,19 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
this.props.edit ? Some(node.comment_view.comment.content) : None, this.props.edit ? Some(node.comment_view.comment.content) : None,
right: () => None, right: () => None,
}); });
let selectedLang = this.props.node
.left()
.map(n => n.comment_view.comment.language_id)
.or(myFirstDiscussionLanguageId(UserService.Instance.myUserInfo));
return ( return (
<div className="mb-3"> <div className="mb-3">
{UserService.Instance.myUserInfo.isSome() ? ( {UserService.Instance.myUserInfo.isSome() ? (
<MarkdownTextArea <MarkdownTextArea
initialContent={initialContent} initialContent={initialContent}
initialLanguageId={selectedLang}
showLanguage
buttonTitle={Some(this.state.buttonTitle)} buttonTitle={Some(this.state.buttonTitle)}
maxLength={None} maxLength={None}
finished={this.state.finished} finished={this.state.finished}
@ -88,6 +99,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
onSubmit={this.handleCommentSubmit} onSubmit={this.handleCommentSubmit}
onReplyCancel={this.handleReplyCancel} onReplyCancel={this.handleReplyCancel}
placeholder={Some(i18n.t("comment_here"))} placeholder={Some(i18n.t("comment_here"))}
allLanguages={this.props.allLanguages}
/> />
) : ( ) : (
<div className="alert alert-warning" role="alert"> <div className="alert alert-warning" role="alert">
@ -104,27 +116,34 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
); );
} }
handleCommentSubmit(msg: { val: string; formId: string }) { handleCommentSubmit(msg: {
val: Option<string>;
formId: string;
languageId: Option<number>;
}) {
let content = msg.val; let content = msg.val;
let language_id = msg.languageId;
this.setState({ formId: Some(msg.formId) }); this.setState({ formId: Some(msg.formId) });
this.props.node.match({ this.props.node.match({
left: node => { left: node => {
if (this.props.edit) { if (this.props.edit) {
let form = new EditComment({ let form = new EditComment({
content: Some(content), content,
distinguished: None, distinguished: None,
form_id: this.state.formId, form_id: this.state.formId,
comment_id: node.comment_view.comment.id, comment_id: node.comment_view.comment.id,
language_id,
auth: auth().unwrap(), auth: auth().unwrap(),
}); });
WebSocketService.Instance.send(wsClient.editComment(form)); WebSocketService.Instance.send(wsClient.editComment(form));
} else { } else {
let form = new CreateComment({ let form = new CreateComment({
content, content: content.unwrap(),
form_id: this.state.formId, form_id: this.state.formId,
post_id: node.comment_view.post.id, post_id: node.comment_view.post.id,
parent_id: Some(node.comment_view.comment.id), parent_id: Some(node.comment_view.comment.id),
language_id,
auth: auth().unwrap(), auth: auth().unwrap(),
}); });
WebSocketService.Instance.send(wsClient.createComment(form)); WebSocketService.Instance.send(wsClient.createComment(form));
@ -132,10 +151,11 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
}, },
right: postId => { right: postId => {
let form = new CreateComment({ let form = new CreateComment({
content, content: content.unwrap(),
form_id: this.state.formId, form_id: this.state.formId,
post_id: postId, post_id: postId,
parent_id: None, parent_id: None,
language_id,
auth: auth().unwrap(), auth: auth().unwrap(),
}); });
WebSocketService.Instance.send(wsClient.createComment(form)); WebSocketService.Instance.send(wsClient.createComment(form));

View file

@ -17,6 +17,7 @@ import {
DeleteComment, DeleteComment,
EditComment, EditComment,
GetComments, GetComments,
Language,
ListingType, ListingType,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
@ -101,6 +102,7 @@ interface CommentNodeProps {
showCommunity?: boolean; showCommunity?: boolean;
enableDownvotes: boolean; enableDownvotes: boolean;
viewType: CommentViewType; viewType: CommentViewType;
allLanguages: Language[];
} }
export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
@ -324,6 +326,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
onReplyCancel={this.handleReplyCancel} onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked} disabled={this.props.locked}
focus focus
allLanguages={this.props.allLanguages}
/> />
)} )}
{!this.state.showEdit && !this.state.collapsed && ( {!this.state.showEdit && !this.state.collapsed && (
@ -1007,6 +1010,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
onReplyCancel={this.handleReplyCancel} onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked} disabled={this.props.locked}
focus focus
allLanguages={this.props.allLanguages}
/> />
)} )}
{!this.state.collapsed && node.children.length > 0 && ( {!this.state.collapsed && node.children.length > 0 && (
@ -1018,6 +1022,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
maxCommentsShown={None} maxCommentsShown={None}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
viewType={this.props.viewType} viewType={this.props.viewType}
allLanguages={this.props.allLanguages}
/> />
)} )}
{/* A collapsed clearfix */} {/* A collapsed clearfix */}
@ -1264,6 +1269,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
form_id: None, // TODO not sure about this form_id: None, // TODO not sure about this
content: None, content: None,
distinguished: Some(!comment.distinguished), distinguished: Some(!comment.distinguished),
language_id: Some(comment.language_id),
auth: auth().unwrap(), auth: auth().unwrap(),
}); });
WebSocketService.Instance.send(wsClient.editComment(form)); WebSocketService.Instance.send(wsClient.editComment(form));

View file

@ -3,6 +3,7 @@ import { Component } from "inferno";
import { import {
CommentNode as CommentNodeI, CommentNode as CommentNodeI,
CommunityModeratorView, CommunityModeratorView,
Language,
PersonViewSafe, PersonViewSafe,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { CommentViewType } from "../../interfaces"; import { CommentViewType } from "../../interfaces";
@ -22,6 +23,7 @@ interface CommentNodesProps {
showCommunity?: boolean; showCommunity?: boolean;
enableDownvotes?: boolean; enableDownvotes?: boolean;
viewType: CommentViewType; viewType: CommentViewType;
allLanguages: Language[];
} }
export class CommentNodes extends Component<CommentNodesProps, any> { export class CommentNodes extends Component<CommentNodesProps, any> {
@ -51,6 +53,7 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
showCommunity={this.props.showCommunity} showCommunity={this.props.showCommunity}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
viewType={this.props.viewType} viewType={this.props.viewType}
allLanguages={this.props.allLanguages}
/> />
))} ))}
</div> </div>

View file

@ -64,6 +64,7 @@ export class CommentReport extends Component<CommentReportProps, any> {
enableDownvotes={true} enableDownvotes={true}
viewOnly={true} viewOnly={true}
showCommunity={true} showCommunity={true}
allLanguages={[]}
/> />
<div> <div>
{i18n.t("reporter")}: <PersonListing person={r.creator} /> {i18n.t("reporter")}: <PersonListing person={r.creator} />

View file

@ -0,0 +1,109 @@
import { Option } from "@sniptt/monads";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import { Language } from "lemmy-js-client";
import { i18n } from "../../i18next";
import { randomStr } from "../../utils";
import { Icon } from "./icon";
interface LanguageSelectProps {
allLanguages: Language[];
selectedLanguageIds: Option<number[]>;
multiple: boolean;
onChange(val: number[]): any;
}
export class LanguageSelect extends Component<LanguageSelectProps, any> {
private id = `language-select-${randomStr()}`;
constructor(props: any, context: any) {
super(props, context);
}
componentDidMount() {
this.setSelectedValues();
}
// Necessary because there is no HTML way to set selected for multiple in value=
setSelectedValues() {
this.props.selectedLanguageIds.map(toString).match({
some: ids => {
var select = (document.getElementById(this.id) as HTMLSelectElement)
.options;
for (let i = 0; i < select.length; i++) {
let o = select[i];
if (ids.includes(o.value)) {
o.selected = true;
}
}
},
none: void 0,
});
}
render() {
let selectedLangs = this.props.selectedLanguageIds;
return (
<div className="form-group row">
<label
className={classNames("col-form-label", {
"col-sm-3": this.props.multiple,
"col-sm-2": !this.props.multiple,
})}
htmlFor={this.id}
>
{i18n.t(this.props.multiple ? "language_plural" : "language")}
</label>
<div
className={classNames("input-group", {
"col-sm-9": this.props.multiple,
"col-sm-10": !this.props.multiple,
})}
>
<select
className="form-control custom-select"
id={this.id}
onChange={linkEvent(this, this.handleLanguageChange)}
aria-label="action"
multiple={this.props.multiple}
>
{this.props.allLanguages.map(l => (
<option
key={l.id}
value={l.id}
selected={selectedLangs.unwrapOr([]).includes(l.id)}
>
{l.name}
</option>
))}
</select>
{this.props.multiple && (
<div className="input-group-append">
<button
className="input-group-text"
onClick={linkEvent(this, this.handleDeselectAll)}
>
<Icon icon="x" />
</button>
</div>
)}
</div>
</div>
);
}
handleLanguageChange(i: LanguageSelect, event: any) {
let options: HTMLOptionElement[] = Array.from(event.target.options);
let selected: number[] = options
.filter(o => o.selected)
.map(o => Number(o.value));
i.props.onChange(selected);
}
handleDeselectAll(i: LanguageSelect, event: any) {
event.preventDefault();
i.props.onChange([]);
}
}

View file

@ -2,7 +2,7 @@ import { None, Option, Some } from "@sniptt/monads";
import autosize from "autosize"; import autosize from "autosize";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { Prompt } from "inferno-router"; import { Prompt } from "inferno-router";
import { toUndefined } from "lemmy-js-client"; import { Language, toUndefined } from "lemmy-js-client";
import { pictrsUri } from "../../env"; import { pictrsUri } from "../../env";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { UserService } from "../../services"; import { UserService } from "../../services";
@ -18,9 +18,11 @@ import {
toast, toast,
} from "../../utils"; } from "../../utils";
import { Icon, Spinner } from "./icon"; import { Icon, Spinner } from "./icon";
import { LanguageSelect } from "./language-select";
interface MarkdownTextAreaProps { interface MarkdownTextAreaProps {
initialContent: Option<string>; initialContent: Option<string>;
initialLanguageId: Option<number>;
placeholder: Option<string>; placeholder: Option<string>;
buttonTitle: Option<string>; buttonTitle: Option<string>;
maxLength: Option<number>; maxLength: Option<number>;
@ -28,14 +30,21 @@ interface MarkdownTextAreaProps {
focus?: boolean; focus?: boolean;
disabled?: boolean; disabled?: boolean;
finished?: boolean; finished?: boolean;
showLanguage?: boolean;
hideNavigationWarnings?: boolean; hideNavigationWarnings?: boolean;
onContentChange?(val: string): any; onContentChange?(val: string): any;
onReplyCancel?(): any; onReplyCancel?(): any;
onSubmit?(msg: { val: string; formId: string }): any; onSubmit?(msg: {
val: Option<string>;
formId: string;
languageId: Option<number>;
}): any;
allLanguages: Language[];
} }
interface MarkdownTextAreaState { interface MarkdownTextAreaState {
content: Option<string>; content: Option<string>;
languageId: Option<number>;
previewMode: boolean; previewMode: boolean;
loading: boolean; loading: boolean;
imageLoading: boolean; imageLoading: boolean;
@ -50,6 +59,7 @@ export class MarkdownTextArea extends Component<
private tribute: any; private tribute: any;
private emptyState: MarkdownTextAreaState = { private emptyState: MarkdownTextAreaState = {
content: this.props.initialContent, content: this.props.initialContent,
languageId: this.props.initialLanguageId,
previewMode: false, previewMode: false,
loading: false, loading: false,
imageLoading: false, imageLoading: false,
@ -58,6 +68,8 @@ export class MarkdownTextArea extends Component<
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
this.handleLanguageChange = this.handleLanguageChange.bind(this);
if (isBrowser()) { if (isBrowser()) {
this.tribute = setupTribute(); this.tribute = setupTribute();
} }
@ -149,6 +161,18 @@ export class MarkdownTextArea extends Component<
{i18n.t("body")} {i18n.t("body")}
</label> </label>
</div> </div>
{this.props.showLanguage && (
<div className="row justify-content-end">
<div className="col-sm-8">
<LanguageSelect
allLanguages={this.props.allLanguages}
selectedLanguageIds={this.state.languageId.map(Array.of)}
multiple={false}
onChange={this.handleLanguageChange}
/>
</div>
</div>
)}
<div className="row"> <div className="row">
<div className="col-sm-12 d-flex flex-wrap"> <div className="col-sm-12 d-flex flex-wrap">
{this.props.buttonTitle.match({ {this.props.buttonTitle.match({
@ -394,10 +418,18 @@ export class MarkdownTextArea extends Component<
i.setState({ previewMode: !i.state.previewMode }); i.setState({ previewMode: !i.state.previewMode });
} }
handleLanguageChange(val: number[]) {
this.setState({ languageId: Some(val[0]) });
}
handleSubmit(i: MarkdownTextArea, event: any) { handleSubmit(i: MarkdownTextArea, event: any) {
event.preventDefault(); event.preventDefault();
i.setState({ loading: true }); i.setState({ loading: true });
let msg = { val: toUndefined(i.state.content), formId: i.formId }; let msg = {
val: i.state.content,
formId: i.formId,
languageId: i.state.languageId,
};
i.props.onSubmit(msg); i.props.onSubmit(msg);
} }

View file

@ -95,11 +95,13 @@ export class RegistrationApplication extends Component<
<div className="col-sm-10"> <div className="col-sm-10">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.denyReason} initialContent={this.state.denyReason}
initialLanguageId={None}
onContentChange={this.handleDenyReasonChange} onContentChange={this.handleDenyReasonChange}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
hideNavigationWarnings hideNavigationWarnings
allLanguages={[]}
/> />
</div> </div>
</div> </div>

View file

@ -212,10 +212,12 @@ export class CommunityForm extends Component<
<div className="col-12 col-sm-10"> <div className="col-12 col-sm-10">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.communityForm.description} initialContent={this.state.communityForm.description}
initialLanguageId={None}
placeholder={Some("description")} placeholder={Some("description")}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
onContentChange={this.handleCommunityDescriptionChange} onContentChange={this.handleCommunityDescriptionChange}
allLanguages={[]}
/> />
</div> </div>
</div> </div>

View file

@ -391,6 +391,7 @@ export class Community extends Component<any, State> {
removeDuplicates removeDuplicates
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
) )
) : this.state.commentsLoading ? ( ) : this.state.commentsLoading ? (
@ -407,6 +408,7 @@ export class Community extends Component<any, State> {
moderators={this.state.communityRes.map(r => r.moderators)} moderators={this.state.communityRes.map(r => r.moderators)}
admins={Some(this.state.siteRes.admins)} admins={Some(this.state.siteRes.admins)}
maxCommentsShown={None} maxCommentsShown={None}
allLanguages={this.state.siteRes.all_languages}
/> />
); );
} }

View file

@ -38,6 +38,7 @@ import {
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
auth, auth,
canCreateCommunity,
commentsToFlatNodes, commentsToFlatNodes,
createCommentLikeRes, createCommentLikeRes,
createPostLikeFindRes, createPostLikeFindRes,
@ -430,7 +431,8 @@ export class Home extends Component<any, HomeState> {
<div className="card border-secondary mb-3"> <div className="card border-secondary mb-3">
<div className="card-body"> <div className="card-body">
{this.trendingCommunities()} {this.trendingCommunities()}
{this.createCommunityButton()} {canCreateCommunity(this.state.siteRes) &&
this.createCommunityButton()}
{this.exploreCommunitiesButton()} {this.exploreCommunitiesButton()}
</div> </div>
</div> </div>
@ -579,6 +581,7 @@ export class Home extends Component<any, HomeState> {
removeDuplicates removeDuplicates
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
) : ( ) : (
<CommentNodes <CommentNodes
@ -591,6 +594,7 @@ export class Home extends Component<any, HomeState> {
showCommunity showCommunity
showContext showContext
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
); );
} }

View file

@ -295,11 +295,13 @@ export class Signup extends Component<any, State> {
<div className="col-sm-10"> <div className="col-sm-10">
<MarkdownTextArea <MarkdownTextArea
initialContent={None} initialContent={None}
initialLanguageId={None}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
onContentChange={this.handleAnswerChange} onContentChange={this.handleAnswerChange}
hideNavigationWarnings hideNavigationWarnings
allLanguages={[]}
/> />
</div> </div>
</div> </div>

View file

@ -212,11 +212,13 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
<div className="col-12"> <div className="col-12">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.siteForm.sidebar} initialContent={this.state.siteForm.sidebar}
initialLanguageId={None}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
onContentChange={this.handleSiteSidebarChange} onContentChange={this.handleSiteSidebarChange}
hideNavigationWarnings hideNavigationWarnings
allLanguages={[]}
/> />
</div> </div>
</div> </div>
@ -227,11 +229,13 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
<div className="col-12"> <div className="col-12">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.siteForm.legal_information} initialContent={this.state.siteForm.legal_information}
initialLanguageId={None}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
onContentChange={this.handleSiteLegalInfoChange} onContentChange={this.handleSiteLegalInfoChange}
hideNavigationWarnings hideNavigationWarnings
allLanguages={[]}
/> />
</div> </div>
</div> </div>
@ -243,11 +247,13 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
<div className="col-12"> <div className="col-12">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.siteForm.application_question} initialContent={this.state.siteForm.application_question}
initialLanguageId={None}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
onContentChange={this.handleSiteApplicationQuestionChange} onContentChange={this.handleSiteApplicationQuestionChange}
hideNavigationWarnings hideNavigationWarnings
allLanguages={[]}
/> />
</div> </div>
</div> </div>

View file

@ -398,6 +398,7 @@ export class Inbox extends Component<any, InboxState> {
showCommunity showCommunity
showContext showContext
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
); );
case ReplyEnum.Mention: case ReplyEnum.Mention:
@ -420,6 +421,7 @@ export class Inbox extends Component<any, InboxState> {
showCommunity showCommunity
showContext showContext
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
); );
case ReplyEnum.Message: case ReplyEnum.Message:
@ -452,6 +454,7 @@ export class Inbox extends Component<any, InboxState> {
showCommunity showCommunity
showContext showContext
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
</div> </div>
); );
@ -473,6 +476,7 @@ export class Inbox extends Component<any, InboxState> {
showCommunity showCommunity
showContext showContext
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
))} ))}
</div> </div>

View file

@ -3,6 +3,7 @@ import { Component } from "inferno";
import { import {
CommentView, CommentView,
GetPersonDetailsResponse, GetPersonDetailsResponse,
Language,
PersonViewSafe, PersonViewSafe,
PostView, PostView,
SortType, SortType,
@ -16,6 +17,7 @@ import { PostListing } from "../post/post-listing";
interface PersonDetailsProps { interface PersonDetailsProps {
personRes: GetPersonDetailsResponse; personRes: GetPersonDetailsResponse;
admins: PersonViewSafe[]; admins: PersonViewSafe[];
allLanguages: Language[];
page: number; page: number;
limit: number; limit: number;
sort: SortType; sort: SortType;
@ -99,6 +101,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
showCommunity showCommunity
showContext showContext
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
allLanguages={this.props.allLanguages}
/> />
); );
} }
@ -114,6 +117,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
showCommunity showCommunity
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw} enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
/> />
); );
} }
@ -171,6 +175,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
showCommunity showCommunity
showContext showContext
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
allLanguages={this.props.allLanguages}
/> />
</div> </div>
); );
@ -189,6 +194,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
moderators={None} moderators={None}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw} enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
/> />
<hr className="my-3" /> <hr className="my-3" />
</> </>

View file

@ -283,6 +283,7 @@ export class Profile extends Component<any, ProfileState> {
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
view={this.state.view} view={this.state.view}
onPageChange={this.handlePageChange} onPageChange={this.handlePageChange}
allLanguages={this.state.siteRes.all_languages}
/> />
</div> </div>

View file

@ -54,6 +54,7 @@ import {
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon"; import { Icon, Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form"; import { ImageUploadForm } from "../common/image-upload-form";
import { LanguageSelect } from "../common/language-select";
import { ListingTypeSelect } from "../common/listing-type-select"; import { ListingTypeSelect } from "../common/listing-type-select";
import { MarkdownTextArea } from "../common/markdown-textarea"; import { MarkdownTextArea } from "../common/markdown-textarea";
import { SortSelect } from "../common/sort-select"; import { SortSelect } from "../common/sort-select";
@ -99,7 +100,8 @@ export class Settings extends Component<any, SettingsState> {
default_sort_type: None, default_sort_type: None,
default_listing_type: None, default_listing_type: None,
theme: None, theme: None,
lang: None, interface_language: None,
discussion_languages: None,
avatar: None, avatar: None,
banner: None, banner: None,
display_name: None, display_name: None,
@ -140,6 +142,8 @@ export class Settings extends Component<any, SettingsState> {
this.handleSortTypeChange = this.handleSortTypeChange.bind(this); this.handleSortTypeChange = this.handleSortTypeChange.bind(this);
this.handleListingTypeChange = this.handleListingTypeChange.bind(this); this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
this.handleBioChange = this.handleBioChange.bind(this); this.handleBioChange = this.handleBioChange.bind(this);
this.handleDiscussionLanguageChange =
this.handleDiscussionLanguageChange.bind(this);
this.handleAvatarUpload = this.handleAvatarUpload.bind(this); this.handleAvatarUpload = this.handleAvatarUpload.bind(this);
this.handleAvatarRemove = this.handleAvatarRemove.bind(this); this.handleAvatarRemove = this.handleAvatarRemove.bind(this);
@ -163,7 +167,7 @@ export class Settings extends Component<any, SettingsState> {
theme: Some(luv.local_user.theme ? luv.local_user.theme : "browser"), theme: Some(luv.local_user.theme ? luv.local_user.theme : "browser"),
default_sort_type: Some(luv.local_user.default_sort_type), default_sort_type: Some(luv.local_user.default_sort_type),
default_listing_type: Some(luv.local_user.default_listing_type), default_listing_type: Some(luv.local_user.default_listing_type),
lang: Some(luv.local_user.lang), interface_language: Some(luv.local_user.interface_language),
avatar: luv.person.avatar, avatar: luv.person.avatar,
banner: luv.person.banner, banner: luv.person.banner,
display_name: luv.person.display_name, display_name: luv.person.display_name,
@ -479,6 +483,8 @@ export class Settings extends Component<any, SettingsState> {
} }
saveUserSettingsHtmlForm() { saveUserSettingsHtmlForm() {
let selectedLangs = this.state.saveUserSettingsForm.discussion_languages;
return ( return (
<> <>
<h5>{i18n.t("settings")}</h5> <h5>{i18n.t("settings")}</h5>
@ -509,11 +515,13 @@ export class Settings extends Component<any, SettingsState> {
<div className="col-sm-9"> <div className="col-sm-9">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.saveUserSettingsForm.bio} initialContent={this.state.saveUserSettingsForm.bio}
initialLanguageId={None}
onContentChange={this.handleBioChange} onContentChange={this.handleBioChange}
maxLength={Some(300)} maxLength={Some(300)}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
hideNavigationWarnings hideNavigationWarnings
allLanguages={this.state.siteRes.all_languages}
/> />
</div> </div>
</div> </div>
@ -578,17 +586,19 @@ export class Settings extends Component<any, SettingsState> {
</div> </div>
<div className="form-group row"> <div className="form-group row">
<label className="col-sm-3" htmlFor="user-language"> <label className="col-sm-3" htmlFor="user-language">
{i18n.t("language")} {i18n.t("interface_language")}
</label> </label>
<div className="col-sm-9"> <div className="col-sm-9">
<select <select
id="user-language" id="user-language"
value={toUndefined(this.state.saveUserSettingsForm.lang)} value={toUndefined(
onChange={linkEvent(this, this.handleLangChange)} this.state.saveUserSettingsForm.interface_language
)}
onChange={linkEvent(this, this.handleInterfaceLangChange)}
className="custom-select w-auto" className="custom-select w-auto"
> >
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
{i18n.t("language")} {i18n.t("interface_language")}
</option> </option>
<option value="browser">{i18n.t("browser_default")}</option> <option value="browser">{i18n.t("browser_default")}</option>
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
@ -604,6 +614,12 @@ export class Settings extends Component<any, SettingsState> {
</select> </select>
</div> </div>
</div> </div>
<LanguageSelect
allLanguages={this.state.siteRes.all_languages}
selectedLanguageIds={selectedLangs}
multiple={true}
onChange={this.handleDiscussionLanguageChange}
/>
<div className="form-group row"> <div className="form-group row">
<label className="col-sm-3" htmlFor="user-theme"> <label className="col-sm-3" htmlFor="user-theme">
{i18n.t("theme")} {i18n.t("theme")}
@ -1040,14 +1056,20 @@ export class Settings extends Component<any, SettingsState> {
i.setState(i.state); i.setState(i.state);
} }
handleLangChange(i: Settings, event: any) { handleInterfaceLangChange(i: Settings, event: any) {
i.state.saveUserSettingsForm.lang = Some(event.target.value); i.state.saveUserSettingsForm.interface_language = Some(event.target.value);
i18n.changeLanguage( i18n.changeLanguage(
getLanguages(i.state.saveUserSettingsForm.lang.unwrap())[0] getLanguages(i.state.saveUserSettingsForm.interface_language.unwrap())[0]
); );
i.setState(i.state); i.setState(i.state);
} }
handleDiscussionLanguageChange(val: number[]) {
this.setState(
s => ((s.saveUserSettingsForm.discussion_languages = Some(val)), s)
);
}
handleSortTypeChange(val: SortType) { handleSortTypeChange(val: SortType) {
this.setState( this.setState(
s => ( s => (

View file

@ -151,6 +151,7 @@ export class CreatePost extends Component<any, CreatePostState> {
params={Some(this.params)} params={Some(this.params)}
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
</div> </div>
</div> </div>

View file

@ -72,7 +72,7 @@ export class MetadataCard extends Component<
), ),
none: <></>, none: <></>,
})} })}
{post.embed_html.isSome() && ( {post.embed_video_url.isSome() && (
<button <button
className="mt-2 btn btn-secondary text-monospace" className="mt-2 btn btn-secondary text-monospace"
onClick={linkEvent(this, this.handleIframeExpand)} onClick={linkEvent(this, this.handleIframeExpand)}
@ -91,7 +91,7 @@ export class MetadataCard extends Component<
none: <></>, none: <></>,
})} })}
{this.state.expanded && {this.state.expanded &&
post.embed_html.match({ post.embed_video_url.match({
some: html => ( some: html => (
<div <div
className="mt-3 mb-2" className="mt-3 mb-2"

View file

@ -6,6 +6,7 @@ import {
CommunityView, CommunityView,
CreatePost, CreatePost,
EditPost, EditPost,
Language,
ListingType, ListingType,
PostResponse, PostResponse,
PostView, PostView,
@ -36,6 +37,7 @@ import {
ghostArchiveUrl, ghostArchiveUrl,
isBrowser, isBrowser,
isImage, isImage,
myFirstDiscussionLanguageId,
pictrsDeleteToast, pictrsDeleteToast,
relTags, relTags,
setupTippy, setupTippy,
@ -48,6 +50,7 @@ import {
wsSubscribe, wsSubscribe,
} from "../../utils"; } from "../../utils";
import { Icon, Spinner } from "../common/icon"; import { Icon, Spinner } from "../common/icon";
import { LanguageSelect } from "../common/language-select";
import { MarkdownTextArea } from "../common/markdown-textarea"; import { MarkdownTextArea } from "../common/markdown-textarea";
import { PostListings } from "./post-listings"; import { PostListings } from "./post-listings";
@ -60,6 +63,7 @@ const MAX_POST_TITLE_LENGTH = 200;
interface PostFormProps { interface PostFormProps {
post_view: Option<PostView>; // If a post is given, that means this is an edit post_view: Option<PostView>; // If a post is given, that means this is an edit
allLanguages: Language[];
communities: Option<CommunityView[]>; communities: Option<CommunityView[]>;
params: Option<PostFormParams>; params: Option<PostFormParams>;
onCancel?(): any; onCancel?(): any;
@ -90,6 +94,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
url: None, url: None,
body: None, body: None,
honeypot: None, honeypot: None,
language_id: None,
auth: undefined, auth: undefined,
}), }),
loading: false, loading: false,
@ -105,6 +110,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
this.fetchSimilarPosts = debounce(this.fetchSimilarPosts.bind(this)); this.fetchSimilarPosts = debounce(this.fetchSimilarPosts.bind(this));
this.fetchPageTitle = debounce(this.fetchPageTitle.bind(this)); this.fetchPageTitle = debounce(this.fetchPageTitle.bind(this));
this.handlePostBodyChange = this.handlePostBodyChange.bind(this); this.handlePostBodyChange = this.handlePostBodyChange.bind(this);
this.handleLanguageChange = this.handleLanguageChange.bind(this);
this.state = this.emptyState; this.state = this.emptyState;
@ -124,6 +130,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
url: pv.post.url, url: pv.post.url,
nsfw: Some(pv.post.nsfw), nsfw: Some(pv.post.nsfw),
honeypot: None, honeypot: None,
language_id: Some(pv.post.language_id),
auth: auth().unwrap(), auth: auth().unwrap(),
}), }),
}; };
@ -172,6 +179,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
} }
render() { render() {
let selectedLangs = this.state.postForm.language_id
.or(myFirstDiscussionLanguageId(UserService.Instance.myUserInfo))
.map(Array.of);
return ( return (
<div> <div>
<Prompt <Prompt
@ -284,6 +295,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
posts={xPosts} posts={xPosts}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw} enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
/> />
</> </>
), ),
@ -325,6 +337,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
posts={sPosts} posts={sPosts}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw} enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
/> />
</> </>
), ),
@ -338,10 +351,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<div className="col-sm-10"> <div className="col-sm-10">
<MarkdownTextArea <MarkdownTextArea
initialContent={this.state.postForm.body} initialContent={this.state.postForm.body}
initialLanguageId={None}
onContentChange={this.handlePostBodyChange} onContentChange={this.handlePostBodyChange}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
allLanguages={this.props.allLanguages}
/> />
</div> </div>
</div> </div>
@ -388,6 +403,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
</div> </div>
</div> </div>
)} )}
<LanguageSelect
allLanguages={this.props.allLanguages}
selectedLanguageIds={selectedLangs}
multiple={false}
onChange={this.handleLanguageChange}
/>
<input <input
tabIndex={-1} tabIndex={-1}
autoComplete="false" autoComplete="false"
@ -453,6 +474,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
body: pForm.body, body: pForm.body,
nsfw: pForm.nsfw, nsfw: pForm.nsfw,
post_id: pv.post.id, post_id: pv.post.id,
language_id: Some(pv.post.language_id),
auth: auth().unwrap(), auth: auth().unwrap(),
}); });
WebSocketService.Instance.send(wsClient.editPost(form)); WebSocketService.Instance.send(wsClient.editPost(form));
@ -559,6 +581,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
i.setState(s => ((s.postForm.nsfw = Some(event.target.checked)), s)); i.setState(s => ((s.postForm.nsfw = Some(event.target.checked)), s));
} }
handleLanguageChange(val: number[]) {
this.setState(s => ((s.postForm.language_id = Some(val[0])), s));
}
handleHoneyPotChange(i: PostForm, event: any) { handleHoneyPotChange(i: PostForm, event: any) {
i.setState(s => ((s.postForm.honeypot = Some(event.target.value)), s)); i.setState(s => ((s.postForm.honeypot = Some(event.target.value)), s));
} }

View file

@ -12,6 +12,7 @@ import {
CreatePostLike, CreatePostLike,
CreatePostReport, CreatePostReport,
DeletePost, DeletePost,
Language,
LockPost, LockPost,
PersonViewSafe, PersonViewSafe,
PostView, PostView,
@ -88,6 +89,7 @@ interface PostListingProps {
duplicates: Option<PostView[]>; duplicates: Option<PostView[]>;
moderators: Option<CommunityModeratorView[]>; moderators: Option<CommunityModeratorView[]>;
admins: Option<PersonViewSafe[]>; admins: Option<PersonViewSafe[]>;
allLanguages: Language[];
showCommunity?: boolean; showCommunity?: boolean;
showBody?: boolean; showBody?: boolean;
enableDownvotes?: boolean; enableDownvotes?: boolean;
@ -169,6 +171,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onCancel={this.handleEditCancel} onCancel={this.handleEditCancel}
enableNsfw={this.props.enableNsfw} enableNsfw={this.props.enableNsfw}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
allLanguages={this.props.allLanguages}
/> />
</div> </div>
)} )}

View file

@ -2,12 +2,13 @@ import { None, Some } from "@sniptt/monads";
import { Component } from "inferno"; import { Component } from "inferno";
import { T } from "inferno-i18next-dess"; import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { PostView } from "lemmy-js-client"; import { Language, PostView } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { PostListing } from "./post-listing"; import { PostListing } from "./post-listing";
interface PostListingsProps { interface PostListingsProps {
posts: PostView[]; posts: PostView[];
allLanguages: Language[];
showCommunity?: boolean; showCommunity?: boolean;
removeDuplicates?: boolean; removeDuplicates?: boolean;
enableDownvotes: boolean; enableDownvotes: boolean;
@ -41,6 +42,7 @@ export class PostListings extends Component<PostListingsProps, any> {
showCommunity={this.props.showCommunity} showCommunity={this.props.showCommunity}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw} enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
/> />
<hr className="my-3" /> <hr className="my-3" />
</> </>

View file

@ -58,6 +58,7 @@ export class PostReport extends Component<PostReportProps, any> {
enableDownvotes={true} enableDownvotes={true}
enableNsfw={true} enableNsfw={true}
viewOnly={true} viewOnly={true}
allLanguages={[]}
/> />
<div> <div>
{i18n.t("reporter")}: <PersonListing person={r.creator} /> {i18n.t("reporter")}: <PersonListing person={r.creator} />

View file

@ -370,11 +370,13 @@ export class Post extends Component<any, PostState> {
admins={Some(this.state.siteRes.admins)} admins={Some(this.state.siteRes.admins)}
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
<div ref={this.state.commentSectionRef} className="mb-2" /> <div ref={this.state.commentSectionRef} className="mb-2" />
<CommentForm <CommentForm
node={Right(res.post_view.post.id)} node={Right(res.post_view.post.id)}
disabled={res.post_view.post.locked} disabled={res.post_view.post.locked}
allLanguages={this.state.siteRes.all_languages}
/> />
<div className="d-block d-md-none"> <div className="d-block d-md-none">
<button <button
@ -508,6 +510,7 @@ export class Post extends Component<any, PostState> {
admins={Some(this.state.siteRes.admins)} admins={Some(this.state.siteRes.admins)}
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
showContext showContext
allLanguages={this.state.siteRes.all_languages}
/> />
</div> </div>
), ),
@ -611,6 +614,7 @@ export class Post extends Component<any, PostState> {
moderators={Some(res.moderators)} moderators={Some(res.moderators)}
admins={Some(this.state.siteRes.admins)} admins={Some(this.state.siteRes.admins)}
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
</div> </div>
), ),

View file

@ -130,10 +130,12 @@ export class PrivateMessageForm extends Component<
<div className="col-sm-10"> <div className="col-sm-10">
<MarkdownTextArea <MarkdownTextArea
initialContent={Some(this.state.privateMessageForm.content)} initialContent={Some(this.state.privateMessageForm.content)}
initialLanguageId={None}
placeholder={None} placeholder={None}
buttonTitle={None} buttonTitle={None}
maxLength={None} maxLength={None}
onContentChange={this.handleContentChange} onContentChange={this.handleContentChange}
allLanguages={[]}
/> />
</div> </div>
</div> </div>

View file

@ -597,6 +597,7 @@ export class Search extends Component<any, SearchState> {
showCommunity showCommunity
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
viewOnly viewOnly
/> />
)} )}
@ -618,6 +619,7 @@ export class Search extends Component<any, SearchState> {
locked locked
noIndent noIndent
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
)} )}
{i.type_ == "communities" && ( {i.type_ == "communities" && (
@ -656,6 +658,7 @@ export class Search extends Component<any, SearchState> {
admins={None} admins={None}
maxCommentsShown={None} maxCommentsShown={None}
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
/> />
); );
} }
@ -685,6 +688,7 @@ export class Search extends Component<any, SearchState> {
admins={None} admins={None}
enableDownvotes={enableDownvotes(this.state.siteRes)} enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)} enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
viewOnly viewOnly
/> />
</div> </div>

View file

@ -1,4 +1,4 @@
import { None, Option, Result, Some } from "@sniptt/monads"; import { Err, None, Ok, Option, Result, Some } from "@sniptt/monads";
import { ClassConstructor, deserialize, serialize } from "class-transformer"; import { ClassConstructor, deserialize, serialize } from "class-transformer";
import emojiShortName from "emoji-short-name"; import emojiShortName from "emoji-short-name";
import { import {
@ -418,7 +418,7 @@ export function getLanguages(
myUserInfo = UserService.Instance.myUserInfo myUserInfo = UserService.Instance.myUserInfo
): string[] { ): string[] {
let myLang = myUserInfo let myLang = myUserInfo
.map(m => m.local_user_view.local_user.lang) .map(m => m.local_user_view.local_user.interface_language)
.unwrapOr("browser"); .unwrapOr("browser");
let lang = override || myLang; let lang = override || myLang;
@ -1461,3 +1461,29 @@ export function postToCommentSortType(sort: SortType): CommentSortType {
return CommentSortType.Top; return CommentSortType.Top;
} }
} }
export function arrayGet<T>(arr: Array<T>, index: number): Result<T, string> {
let out = arr.at(index);
if (out == undefined) {
return Err("Index undefined");
} else {
return Ok(out);
}
}
export function myFirstDiscussionLanguageId(
myUserInfo = UserService.Instance.myUserInfo
): Option<number> {
return myUserInfo.andThen(mui =>
arrayGet(mui.discussion_languages, 0)
.ok()
.map(i => i.id)
);
}
export function canCreateCommunity(siteRes: GetSiteResponse): boolean {
let adminOnly = siteRes.site_view
.map(s => s.site.community_creation_admin_only)
.unwrapOr(false);
return !adminOnly || amAdmin(Some(siteRes.admins));
}

View file

@ -5224,10 +5224,10 @@ lcid@^1.0.0:
dependencies: dependencies:
invert-kv "^1.0.0" invert-kv "^1.0.0"
lemmy-js-client@0.17.0-rc.43: lemmy-js-client@0.17.0-rc.44:
version "0.17.0-rc.43" version "0.17.0-rc.44"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.43.tgz#30e985365a93d72184646fdfe359f39ccc2e2091" resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.44.tgz#a5bd870b73bc25c3d8b47569ddcd66ef506b73ee"
integrity sha512-/+TOTZazoi74zwc8H2AJMd/Znrdnqfi0+TrfnmqvQ3fzrOl741ojEURxAHw3NsgW9b8HkubXZFLsi1RVR99UqA== integrity sha512-xXxjmDhRWCjRtfAIy8LwHDheR+VzQ4Co5xJyop1mXHtxrlUJx0mrcvXu84LnJ00zrqGa8lpE5R2IpbsRg9DsZA==
levn@^0.4.1: levn@^0.4.1:
version "0.4.1" version "0.4.1"