1 import { None, Option, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
5 BlockCommunityResponse,
23 } from "lemmy-js-client";
24 import { Subscription } from "rxjs";
25 import { i18n, languages } from "../../i18next";
26 import { UserService, WebSocketService } from "../../services";
29 capitalizeFirstLetter,
54 import { HtmlTags } from "../common/html-tags";
55 import { Icon, Spinner } from "../common/icon";
56 import { ImageUploadForm } from "../common/image-upload-form";
57 import { LanguageSelect } from "../common/language-select";
58 import { ListingTypeSelect } from "../common/listing-type-select";
59 import { MarkdownTextArea } from "../common/markdown-textarea";
60 import { SortSelect } from "../common/sort-select";
61 import { CommunityLink } from "../community/community-link";
62 import { PersonListing } from "./person-listing";
66 Choices = require("choices.js");
69 interface SettingsState {
70 saveUserSettingsForm: SaveUserSettings;
71 changePasswordForm: ChangePassword;
72 deleteAccountForm: DeleteAccount;
73 personBlocks: PersonBlockView[];
74 blockPerson: Option<PersonViewSafe>;
75 communityBlocks: CommunityBlockView[];
76 blockCommunityId: number;
77 blockCommunity?: CommunityView;
80 saveUserSettingsLoading: boolean;
81 changePasswordLoading: boolean;
82 deleteAccountLoading: boolean;
83 deleteAccountShowConfirm: boolean;
84 siteRes: GetSiteResponse;
87 export class Settings extends Component<any, SettingsState> {
88 private isoData = setIsoData(this.context);
89 private blockPersonChoices: any;
90 private blockCommunityChoices: any;
91 private subscription: Subscription;
92 private emptyState: SettingsState = {
93 saveUserSettingsForm: new SaveUserSettings({
97 show_read_posts: None,
98 show_bot_accounts: None,
99 show_new_post_notifs: None,
100 default_sort_type: None,
101 default_listing_type: None,
103 interface_language: None,
104 discussion_languages: None,
110 matrix_user_id: None,
111 send_notifications_to_email: None,
115 changePasswordForm: new ChangePassword({
116 new_password: undefined,
117 new_password_verify: undefined,
118 old_password: undefined,
121 saveUserSettingsLoading: false,
122 changePasswordLoading: false,
123 deleteAccountLoading: false,
124 deleteAccountShowConfirm: false,
125 deleteAccountForm: new DeleteAccount({
133 currentTab: "settings",
134 siteRes: this.isoData.site_res,
138 constructor(props: any, context: any) {
139 super(props, context);
141 this.state = this.emptyState;
142 this.handleSortTypeChange = this.handleSortTypeChange.bind(this);
143 this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
144 this.handleBioChange = this.handleBioChange.bind(this);
145 this.handleDiscussionLanguageChange =
146 this.handleDiscussionLanguageChange.bind(this);
148 this.handleAvatarUpload = this.handleAvatarUpload.bind(this);
149 this.handleAvatarRemove = this.handleAvatarRemove.bind(this);
151 this.handleBannerUpload = this.handleBannerUpload.bind(this);
152 this.handleBannerRemove = this.handleBannerRemove.bind(this);
154 this.parseMessage = this.parseMessage.bind(this);
155 this.subscription = wsSubscribe(this.parseMessage);
157 if (UserService.Instance.myUserInfo.isSome()) {
158 let mui = UserService.Instance.myUserInfo.unwrap();
159 let luv = mui.local_user_view;
162 personBlocks: mui.person_blocks,
163 communityBlocks: mui.community_blocks,
164 saveUserSettingsForm: {
165 ...this.state.saveUserSettingsForm,
166 show_nsfw: Some(luv.local_user.show_nsfw),
167 theme: Some(luv.local_user.theme ? luv.local_user.theme : "browser"),
168 default_sort_type: Some(luv.local_user.default_sort_type),
169 default_listing_type: Some(luv.local_user.default_listing_type),
170 interface_language: Some(luv.local_user.interface_language),
171 discussion_languages: Some(mui.discussion_languages),
172 avatar: luv.person.avatar,
173 banner: luv.person.banner,
174 display_name: luv.person.display_name,
175 show_avatars: Some(luv.local_user.show_avatars),
176 bot_account: Some(luv.person.bot_account),
177 show_bot_accounts: Some(luv.local_user.show_bot_accounts),
178 show_scores: Some(luv.local_user.show_scores),
179 show_read_posts: Some(luv.local_user.show_read_posts),
180 show_new_post_notifs: Some(luv.local_user.show_new_post_notifs),
181 email: luv.local_user.email,
183 send_notifications_to_email: Some(
184 luv.local_user.send_notifications_to_email
186 matrix_user_id: luv.person.matrix_user_id,
192 async componentDidMount() {
194 this.setState({ themeList: await fetchThemeList() });
197 componentWillUnmount() {
198 this.subscription.unsubscribe();
201 get documentTitle(): string {
202 return i18n.t("settings");
207 <div className="container-lg">
210 title={this.documentTitle}
211 path={this.context.router.route.match.url}
212 description={Some(this.documentTitle)}
213 image={this.state.saveUserSettingsForm.avatar}
215 <ul className="nav nav-tabs mb-2">
216 <li className="nav-item">
218 className={`nav-link btn ${
219 this.state.currentTab == "settings" && "active"
222 { ctx: this, tab: "settings" },
229 <li className="nav-item">
231 className={`nav-link btn ${
232 this.state.currentTab == "blocks" && "active"
235 { ctx: this, tab: "blocks" },
243 {this.state.currentTab == "settings" && this.userSettings()}
244 {this.state.currentTab == "blocks" && this.blockCards()}
252 <div className="row">
253 <div className="col-12 col-md-6">
254 <div className="card border-secondary mb-3">
255 <div className="card-body">{this.saveUserSettingsHtmlForm()}</div>
258 <div className="col-12 col-md-6">
259 <div className="card border-secondary mb-3">
260 <div className="card-body">{this.changePasswordHtmlForm()}</div>
269 <div className="row">
270 <div className="col-12 col-md-6">
271 <div className="card border-secondary mb-3">
272 <div className="card-body">{this.blockUserCard()}</div>
275 <div className="col-12 col-md-6">
276 <div className="card border-secondary mb-3">
277 <div className="card-body">{this.blockCommunityCard()}</div>
284 changePasswordHtmlForm() {
287 <h5>{i18n.t("change_password")}</h5>
288 <form onSubmit={linkEvent(this, this.handleChangePasswordSubmit)}>
289 <div className="form-group row">
290 <label className="col-sm-5 col-form-label" htmlFor="user-password">
291 {i18n.t("new_password")}
293 <div className="col-sm-7">
297 className="form-control"
298 value={this.state.changePasswordForm.new_password}
299 autoComplete="new-password"
301 onInput={linkEvent(this, this.handleNewPasswordChange)}
305 <div className="form-group row">
307 className="col-sm-5 col-form-label"
308 htmlFor="user-verify-password"
310 {i18n.t("verify_password")}
312 <div className="col-sm-7">
315 id="user-verify-password"
316 className="form-control"
317 value={this.state.changePasswordForm.new_password_verify}
318 autoComplete="new-password"
320 onInput={linkEvent(this, this.handleNewPasswordVerifyChange)}
324 <div className="form-group row">
326 className="col-sm-5 col-form-label"
327 htmlFor="user-old-password"
329 {i18n.t("old_password")}
331 <div className="col-sm-7">
334 id="user-old-password"
335 className="form-control"
336 value={this.state.changePasswordForm.old_password}
337 autoComplete="new-password"
339 onInput={linkEvent(this, this.handleOldPasswordChange)}
343 <div className="form-group">
344 <button type="submit" className="btn btn-block btn-secondary mr-4">
345 {this.state.changePasswordLoading ? (
348 capitalizeFirstLetter(i18n.t("save"))
360 {this.blockUserForm()}
361 {this.blockedUsersList()}
369 <h5>{i18n.t("blocked_users")}</h5>
370 <ul className="list-unstyled mb-0">
371 {this.state.personBlocks.map(pb => (
372 <li key={pb.target.id}>
374 <PersonListing person={pb.target} />
376 className="btn btn-sm"
378 { ctx: this, recipientId: pb.target.id },
379 this.handleUnblockPerson
381 data-tippy-content={i18n.t("unblock_user")}
383 <Icon icon="x" classes="icon-inline" />
395 <div className="form-group row">
397 className="col-md-4 col-form-label"
398 htmlFor="block-person-filter"
400 {i18n.t("block_user")}
402 <div className="col-md-8">
404 className="form-control"
405 id="block-person-filter"
406 value={this.state.blockPerson.map(p => p.person.id).unwrapOr(0)}
408 <option value="0">—</option>
409 {this.state.blockPerson.match({
410 some: personView => (
411 <option value={personView.person.id}>
412 {personSelectName(personView)}
423 blockCommunityCard() {
426 {this.blockCommunityForm()}
427 {this.blockedCommunitiesList()}
432 blockedCommunitiesList() {
435 <h5>{i18n.t("blocked_communities")}</h5>
436 <ul className="list-unstyled mb-0">
437 {this.state.communityBlocks.map(cb => (
438 <li key={cb.community.id}>
440 <CommunityLink community={cb.community} />
442 className="btn btn-sm"
444 { ctx: this, communityId: cb.community.id },
445 this.handleUnblockCommunity
447 data-tippy-content={i18n.t("unblock_community")}
449 <Icon icon="x" classes="icon-inline" />
459 blockCommunityForm() {
461 <div className="form-group row">
463 className="col-md-4 col-form-label"
464 htmlFor="block-community-filter"
466 {i18n.t("block_community")}
468 <div className="col-md-8">
470 className="form-control"
471 id="block-community-filter"
472 value={this.state.blockCommunityId}
474 <option value="0">—</option>
475 {this.state.blockCommunity && (
476 <option value={this.state.blockCommunity.community.id}>
477 {communitySelectName(this.state.blockCommunity)}
486 saveUserSettingsHtmlForm() {
487 let selectedLangs = this.state.saveUserSettingsForm.discussion_languages;
491 <h5>{i18n.t("settings")}</h5>
492 <form onSubmit={linkEvent(this, this.handleSaveSettingsSubmit)}>
493 <div className="form-group row">
494 <label className="col-sm-5 col-form-label" htmlFor="display-name">
495 {i18n.t("display_name")}
497 <div className="col-sm-7">
501 className="form-control"
502 placeholder={i18n.t("optional")}
504 this.state.saveUserSettingsForm.display_name
506 onInput={linkEvent(this, this.handleDisplayNameChange)}
507 pattern="^(?!@)(.+)$"
512 <div className="form-group row">
513 <label className="col-sm-3 col-form-label" htmlFor="user-bio">
516 <div className="col-sm-9">
518 initialContent={this.state.saveUserSettingsForm.bio}
519 initialLanguageId={None}
520 onContentChange={this.handleBioChange}
521 maxLength={Some(300)}
524 hideNavigationWarnings
525 allLanguages={this.state.siteRes.all_languages}
526 siteLanguages={this.state.siteRes.discussion_languages}
530 <div className="form-group row">
531 <label className="col-sm-3 col-form-label" htmlFor="user-email">
534 <div className="col-sm-9">
538 className="form-control"
539 placeholder={i18n.t("optional")}
540 value={toUndefined(this.state.saveUserSettingsForm.email)}
541 onInput={linkEvent(this, this.handleEmailChange)}
546 <div className="form-group row">
547 <label className="col-sm-5 col-form-label" htmlFor="matrix-user-id">
548 <a href={elementUrl} rel={relTags}>
549 {i18n.t("matrix_user_id")}
552 <div className="col-sm-7">
556 className="form-control"
557 placeholder="@user:example.com"
559 this.state.saveUserSettingsForm.matrix_user_id
561 onInput={linkEvent(this, this.handleMatrixUserIdChange)}
562 pattern="^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
566 <div className="form-group row">
567 <label className="col-sm-3">{i18n.t("avatar")}</label>
568 <div className="col-sm-9">
570 uploadTitle={i18n.t("upload_avatar")}
571 imageSrc={this.state.saveUserSettingsForm.avatar}
572 onUpload={this.handleAvatarUpload}
573 onRemove={this.handleAvatarRemove}
578 <div className="form-group row">
579 <label className="col-sm-3">{i18n.t("banner")}</label>
580 <div className="col-sm-9">
582 uploadTitle={i18n.t("upload_banner")}
583 imageSrc={this.state.saveUserSettingsForm.banner}
584 onUpload={this.handleBannerUpload}
585 onRemove={this.handleBannerRemove}
589 <div className="form-group row">
590 <label className="col-sm-3" htmlFor="user-language">
591 {i18n.t("interface_language")}
593 <div className="col-sm-9">
597 this.state.saveUserSettingsForm.interface_language
599 onChange={linkEvent(this, this.handleInterfaceLangChange)}
600 className="custom-select w-auto"
602 <option disabled aria-hidden="true">
603 {i18n.t("interface_language")}
605 <option value="browser">{i18n.t("browser_default")}</option>
606 <option disabled aria-hidden="true">
610 .sort((a, b) => a.code.localeCompare(b.code))
612 <option key={lang.code} value={lang.code}>
620 allLanguages={this.state.siteRes.all_languages}
621 siteLanguages={this.state.siteRes.discussion_languages}
622 selectedLanguageIds={selectedLangs}
625 onChange={this.handleDiscussionLanguageChange}
627 <div className="form-group row">
628 <label className="col-sm-3" htmlFor="user-theme">
631 <div className="col-sm-9">
634 value={toUndefined(this.state.saveUserSettingsForm.theme)}
635 onChange={linkEvent(this, this.handleThemeChange)}
636 className="custom-select w-auto"
638 <option disabled aria-hidden="true">
641 <option value="browser">{i18n.t("browser_default")}</option>
642 {this.state.themeList.map(theme => (
643 <option key={theme} value={theme}>
650 <form className="form-group row">
651 <label className="col-sm-3">{i18n.t("type")}</label>
652 <div className="col-sm-9">
655 Object.values(ListingType)[
656 this.state.saveUserSettingsForm.default_listing_type.unwrapOr(
661 showLocal={showLocal(this.isoData)}
663 onChange={this.handleListingTypeChange}
667 <form className="form-group row">
668 <label className="col-sm-3">{i18n.t("sort_type")}</label>
669 <div className="col-sm-9">
672 Object.values(SortType)[
673 this.state.saveUserSettingsForm.default_sort_type.unwrapOr(
678 onChange={this.handleSortTypeChange}
682 {enableNsfw(this.state.siteRes) && (
683 <div className="form-group">
684 <div className="form-check">
686 className="form-check-input"
689 checked={toUndefined(
690 this.state.saveUserSettingsForm.show_nsfw
692 onChange={linkEvent(this, this.handleShowNsfwChange)}
694 <label className="form-check-label" htmlFor="user-show-nsfw">
695 {i18n.t("show_nsfw")}
700 <div className="form-group">
701 <div className="form-check">
703 className="form-check-input"
704 id="user-show-scores"
706 checked={toUndefined(
707 this.state.saveUserSettingsForm.show_scores
709 onChange={linkEvent(this, this.handleShowScoresChange)}
711 <label className="form-check-label" htmlFor="user-show-scores">
712 {i18n.t("show_scores")}
716 <div className="form-group">
717 <div className="form-check">
719 className="form-check-input"
720 id="user-show-avatars"
722 checked={toUndefined(
723 this.state.saveUserSettingsForm.show_avatars
725 onChange={linkEvent(this, this.handleShowAvatarsChange)}
727 <label className="form-check-label" htmlFor="user-show-avatars">
728 {i18n.t("show_avatars")}
732 <div className="form-group">
733 <div className="form-check">
735 className="form-check-input"
736 id="user-bot-account"
738 checked={toUndefined(
739 this.state.saveUserSettingsForm.bot_account
741 onChange={linkEvent(this, this.handleBotAccount)}
743 <label className="form-check-label" htmlFor="user-bot-account">
744 {i18n.t("bot_account")}
748 <div className="form-group">
749 <div className="form-check">
751 className="form-check-input"
752 id="user-show-bot-accounts"
754 checked={toUndefined(
755 this.state.saveUserSettingsForm.show_bot_accounts
757 onChange={linkEvent(this, this.handleShowBotAccounts)}
760 className="form-check-label"
761 htmlFor="user-show-bot-accounts"
763 {i18n.t("show_bot_accounts")}
767 <div className="form-group">
768 <div className="form-check">
770 className="form-check-input"
771 id="user-show-read-posts"
773 checked={toUndefined(
774 this.state.saveUserSettingsForm.show_read_posts
776 onChange={linkEvent(this, this.handleReadPosts)}
779 className="form-check-label"
780 htmlFor="user-show-read-posts"
782 {i18n.t("show_read_posts")}
786 <div className="form-group">
787 <div className="form-check">
789 className="form-check-input"
790 id="user-show-new-post-notifs"
792 checked={toUndefined(
793 this.state.saveUserSettingsForm.show_new_post_notifs
795 onChange={linkEvent(this, this.handleShowNewPostNotifs)}
798 className="form-check-label"
799 htmlFor="user-show-new-post-notifs"
801 {i18n.t("show_new_post_notifs")}
805 <div className="form-group">
806 <div className="form-check">
808 className="form-check-input"
809 id="user-send-notifications-to-email"
811 disabled={!this.state.saveUserSettingsForm.email}
812 checked={toUndefined(
813 this.state.saveUserSettingsForm.send_notifications_to_email
817 this.handleSendNotificationsToEmailChange
821 className="form-check-label"
822 htmlFor="user-send-notifications-to-email"
824 {i18n.t("send_notifications_to_email")}
828 <div className="form-group">
829 <button type="submit" className="btn btn-block btn-secondary mr-4">
830 {this.state.saveUserSettingsLoading ? (
833 capitalizeFirstLetter(i18n.t("save"))
838 <div className="form-group">
840 className="btn btn-block btn-danger"
843 this.handleDeleteAccountShowConfirmToggle
846 {i18n.t("delete_account")}
848 {this.state.deleteAccountShowConfirm && (
850 <div className="my-2 alert alert-danger" role="alert">
851 {i18n.t("delete_account_confirm")}
855 value={this.state.deleteAccountForm.password}
856 autoComplete="new-password"
860 this.handleDeleteAccountPasswordChange
862 className="form-control my-2"
865 className="btn btn-danger mr-4"
866 disabled={!this.state.deleteAccountForm.password}
867 onClick={linkEvent(this, this.handleDeleteAccount)}
869 {this.state.deleteAccountLoading ? (
872 capitalizeFirstLetter(i18n.t("delete"))
876 className="btn btn-secondary"
879 this.handleDeleteAccountShowConfirmToggle
892 setupBlockPersonChoices() {
894 let selectId: any = document.getElementById("block-person-filter");
896 this.blockPersonChoices = new Choices(selectId, choicesConfig);
897 this.blockPersonChoices.passedElement.element.addEventListener(
900 this.handleBlockPerson(Number(e.detail.choice.value));
904 this.blockPersonChoices.passedElement.element.addEventListener(
906 debounce(async (e: any) => {
908 let persons = (await fetchUsers(e.detail.value)).users;
909 let choices = persons.map(pvs => personToChoice(pvs));
910 this.blockPersonChoices.setChoices(
926 setupBlockCommunityChoices() {
928 let selectId: any = document.getElementById("block-community-filter");
930 this.blockCommunityChoices = new Choices(selectId, choicesConfig);
931 this.blockCommunityChoices.passedElement.element.addEventListener(
934 this.handleBlockCommunity(Number(e.detail.choice.value));
938 this.blockCommunityChoices.passedElement.element.addEventListener(
940 debounce(async (e: any) => {
942 let communities = (await fetchCommunities(e.detail.value))
944 let choices = communities.map(cv => communityToChoice(cv));
945 this.blockCommunityChoices.setChoices(
961 handleBlockPerson(personId: number) {
963 let blockUserForm = new BlockPerson({
966 auth: auth().unwrap(),
968 WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
972 handleUnblockPerson(i: { ctx: Settings; recipientId: number }) {
973 let blockUserForm = new BlockPerson({
974 person_id: i.recipientId,
976 auth: auth().unwrap(),
978 WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
981 handleBlockCommunity(community_id: number) {
982 if (community_id != 0) {
983 let blockCommunityForm = new BlockCommunity({
986 auth: auth().unwrap(),
988 WebSocketService.Instance.send(
989 wsClient.blockCommunity(blockCommunityForm)
994 handleUnblockCommunity(i: { ctx: Settings; communityId: number }) {
995 let blockCommunityForm = new BlockCommunity({
996 community_id: i.communityId,
998 auth: auth().unwrap(),
1000 WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
1003 handleShowNsfwChange(i: Settings, event: any) {
1004 i.state.saveUserSettingsForm.show_nsfw = Some(event.target.checked);
1005 i.setState(i.state);
1008 handleShowAvatarsChange(i: Settings, event: any) {
1009 i.state.saveUserSettingsForm.show_avatars = Some(event.target.checked);
1010 UserService.Instance.myUserInfo.match({
1012 (mui.local_user_view.local_user.show_avatars = event.target.checked),
1015 i.setState(i.state);
1018 handleBotAccount(i: Settings, event: any) {
1019 i.state.saveUserSettingsForm.bot_account = Some(event.target.checked);
1020 i.setState(i.state);
1023 handleShowBotAccounts(i: Settings, event: any) {
1024 i.state.saveUserSettingsForm.show_bot_accounts = Some(event.target.checked);
1025 i.setState(i.state);
1028 handleReadPosts(i: Settings, event: any) {
1029 i.state.saveUserSettingsForm.show_read_posts = Some(event.target.checked);
1030 i.setState(i.state);
1033 handleShowNewPostNotifs(i: Settings, event: any) {
1034 i.state.saveUserSettingsForm.show_new_post_notifs = Some(
1035 event.target.checked
1037 i.setState(i.state);
1040 handleShowScoresChange(i: Settings, event: any) {
1041 i.state.saveUserSettingsForm.show_scores = Some(event.target.checked);
1042 UserService.Instance.myUserInfo.match({
1044 (mui.local_user_view.local_user.show_scores = event.target.checked),
1047 i.setState(i.state);
1050 handleSendNotificationsToEmailChange(i: Settings, event: any) {
1051 i.state.saveUserSettingsForm.send_notifications_to_email = Some(
1052 event.target.checked
1054 i.setState(i.state);
1057 handleThemeChange(i: Settings, event: any) {
1058 i.state.saveUserSettingsForm.theme = Some(event.target.value);
1059 setTheme(event.target.value, true);
1060 i.setState(i.state);
1063 handleInterfaceLangChange(i: Settings, event: any) {
1064 i.state.saveUserSettingsForm.interface_language = Some(event.target.value);
1065 i18n.changeLanguage(
1066 getLanguages(i.state.saveUserSettingsForm.interface_language.unwrap())[0]
1068 i.setState(i.state);
1071 handleDiscussionLanguageChange(val: number[]) {
1073 s => ((s.saveUserSettingsForm.discussion_languages = Some(val)), s)
1077 handleSortTypeChange(val: SortType) {
1080 (s.saveUserSettingsForm.default_sort_type = Some(
1081 Object.keys(SortType).indexOf(val)
1088 handleListingTypeChange(val: ListingType) {
1091 (s.saveUserSettingsForm.default_listing_type = Some(
1092 Object.keys(ListingType).indexOf(val)
1099 handleEmailChange(i: Settings, event: any) {
1100 i.state.saveUserSettingsForm.email = Some(event.target.value);
1101 i.setState(i.state);
1104 handleBioChange(val: string) {
1105 this.setState(s => ((s.saveUserSettingsForm.bio = Some(val)), s));
1108 handleAvatarUpload(url: string) {
1109 this.setState(s => ((s.saveUserSettingsForm.avatar = Some(url)), s));
1112 handleAvatarRemove() {
1113 this.setState(s => ((s.saveUserSettingsForm.avatar = Some("")), s));
1116 handleBannerUpload(url: string) {
1117 this.setState(s => ((s.saveUserSettingsForm.banner = Some(url)), s));
1120 handleBannerRemove() {
1121 this.setState(s => ((s.saveUserSettingsForm.banner = Some("")), s));
1124 handleDisplayNameChange(i: Settings, event: any) {
1125 i.state.saveUserSettingsForm.display_name = Some(event.target.value);
1126 i.setState(i.state);
1129 handleMatrixUserIdChange(i: Settings, event: any) {
1130 i.state.saveUserSettingsForm.matrix_user_id = Some(event.target.value);
1131 i.setState(i.state);
1134 handleNewPasswordChange(i: Settings, event: any) {
1135 i.state.changePasswordForm.new_password = event.target.value;
1136 if (i.state.changePasswordForm.new_password == "") {
1137 i.state.changePasswordForm.new_password = undefined;
1139 i.setState(i.state);
1142 handleNewPasswordVerifyChange(i: Settings, event: any) {
1143 i.state.changePasswordForm.new_password_verify = event.target.value;
1144 if (i.state.changePasswordForm.new_password_verify == "") {
1145 i.state.changePasswordForm.new_password_verify = undefined;
1147 i.setState(i.state);
1150 handleOldPasswordChange(i: Settings, event: any) {
1151 i.state.changePasswordForm.old_password = event.target.value;
1152 if (i.state.changePasswordForm.old_password == "") {
1153 i.state.changePasswordForm.old_password = undefined;
1155 i.setState(i.state);
1158 handleSaveSettingsSubmit(i: Settings, event: any) {
1159 event.preventDefault();
1160 i.setState({ saveUserSettingsLoading: true });
1161 i.setState(s => ((s.saveUserSettingsForm.auth = auth().unwrap()), s));
1163 let form = new SaveUserSettings({ ...i.state.saveUserSettingsForm });
1164 WebSocketService.Instance.send(wsClient.saveUserSettings(form));
1167 handleChangePasswordSubmit(i: Settings, event: any) {
1168 event.preventDefault();
1169 i.setState({ changePasswordLoading: true });
1170 i.setState(s => ((s.changePasswordForm.auth = auth().unwrap()), s));
1172 let form = new ChangePassword({ ...i.state.changePasswordForm });
1174 WebSocketService.Instance.send(wsClient.changePassword(form));
1177 handleDeleteAccountShowConfirmToggle(i: Settings, event: any) {
1178 event.preventDefault();
1179 i.setState({ deleteAccountShowConfirm: !i.state.deleteAccountShowConfirm });
1182 handleDeleteAccountPasswordChange(i: Settings, event: any) {
1183 i.state.deleteAccountForm.password = event.target.value;
1184 i.setState(i.state);
1187 handleDeleteAccount(i: Settings, event: any) {
1188 event.preventDefault();
1189 i.setState({ deleteAccountLoading: true });
1190 i.setState(s => ((s.deleteAccountForm.auth = auth().unwrap()), s));
1192 let form = new DeleteAccount({ ...i.state.deleteAccountForm });
1194 WebSocketService.Instance.send(wsClient.deleteAccount(form));
1197 handleSwitchTab(i: { ctx: Settings; tab: string }) {
1198 i.ctx.setState({ currentTab: i.tab });
1200 if (i.ctx.state.currentTab == "blocks") {
1201 i.ctx.setupBlockPersonChoices();
1202 i.ctx.setupBlockCommunityChoices();
1206 parseMessage(msg: any) {
1207 let op = wsUserOp(msg);
1211 saveUserSettingsLoading: false,
1212 changePasswordLoading: false,
1213 deleteAccountLoading: false,
1215 toast(i18n.t(msg.error), "danger");
1217 } else if (op == UserOperation.SaveUserSettings) {
1218 let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
1219 UserService.Instance.login(data);
1221 this.setState({ saveUserSettingsLoading: false });
1222 toast(i18n.t("saved"));
1223 window.scrollTo(0, 0);
1224 } else if (op == UserOperation.ChangePassword) {
1225 let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
1226 UserService.Instance.login(data);
1227 this.setState({ changePasswordLoading: false });
1228 window.scrollTo(0, 0);
1229 toast(i18n.t("password_changed"));
1230 } else if (op == UserOperation.DeleteAccount) {
1232 deleteAccountLoading: false,
1233 deleteAccountShowConfirm: false,
1235 UserService.Instance.logout();
1236 window.location.href = "/";
1237 } else if (op == UserOperation.BlockPerson) {
1238 let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
1239 updatePersonBlock(data).match({
1240 some: blocks => this.setState({ personBlocks: blocks }),
1243 } else if (op == UserOperation.BlockCommunity) {
1244 let data = wsJsonToRes<BlockCommunityResponse>(
1246 BlockCommunityResponse
1248 updateCommunityBlock(data).match({
1249 some: blocks => this.setState({ communityBlocks: blocks }),