1 import { Component, linkEvent } from "inferno";
4 BlockCommunityResponse,
21 } from "lemmy-js-client";
22 import { Subscription } from "rxjs";
23 import { i18n, languages } from "../../i18next";
24 import { UserService, WebSocketService } from "../../services";
26 capitalizeFirstLetter,
52 import { HtmlTags } from "../common/html-tags";
53 import { Icon, Spinner } from "../common/icon";
54 import { ImageUploadForm } from "../common/image-upload-form";
55 import { LanguageSelect } from "../common/language-select";
56 import { ListingTypeSelect } from "../common/listing-type-select";
57 import { MarkdownTextArea } from "../common/markdown-textarea";
58 import { SortSelect } from "../common/sort-select";
59 import { CommunityLink } from "../community/community-link";
60 import { PersonListing } from "./person-listing";
64 Choices = require("choices.js");
67 interface SettingsState {
68 // TODO redo these forms
69 saveUserSettingsForm: {
72 default_sort_type?: number;
73 default_listing_type?: number;
74 interface_language?: string;
77 display_name?: string;
80 matrix_user_id?: string;
81 show_avatars?: boolean;
82 show_scores?: boolean;
83 send_notifications_to_email?: boolean;
84 bot_account?: boolean;
85 show_bot_accounts?: boolean;
86 show_read_posts?: boolean;
87 show_new_post_notifs?: boolean;
88 discussion_languages?: number[];
89 generate_totp_2fa?: boolean;
92 new_password?: string;
93 new_password_verify?: string;
94 old_password?: string;
99 personBlocks: PersonBlockView[];
100 blockPerson?: PersonViewSafe;
101 communityBlocks: CommunityBlockView[];
102 blockCommunityId: number;
103 blockCommunity?: CommunityView;
106 saveUserSettingsLoading: boolean;
107 changePasswordLoading: boolean;
108 deleteAccountLoading: boolean;
109 deleteAccountShowConfirm: boolean;
110 siteRes: GetSiteResponse;
113 export class Settings extends Component<any, SettingsState> {
114 private isoData = setIsoData(this.context);
115 private blockPersonChoices: any;
116 private blockCommunityChoices: any;
117 private subscription?: Subscription;
118 state: SettingsState = {
119 saveUserSettingsForm: {},
120 changePasswordForm: {},
121 saveUserSettingsLoading: false,
122 changePasswordLoading: false,
123 deleteAccountLoading: false,
124 deleteAccountShowConfirm: false,
125 deleteAccountForm: {},
129 currentTab: "settings",
130 siteRes: this.isoData.site_res,
134 constructor(props: any, context: any) {
135 super(props, context);
137 this.handleSortTypeChange = this.handleSortTypeChange.bind(this);
138 this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
139 this.handleBioChange = this.handleBioChange.bind(this);
140 this.handleDiscussionLanguageChange =
141 this.handleDiscussionLanguageChange.bind(this);
143 this.handleAvatarUpload = this.handleAvatarUpload.bind(this);
144 this.handleAvatarRemove = this.handleAvatarRemove.bind(this);
146 this.handleBannerUpload = this.handleBannerUpload.bind(this);
147 this.handleBannerRemove = this.handleBannerRemove.bind(this);
149 this.parseMessage = this.parseMessage.bind(this);
150 this.subscription = wsSubscribe(this.parseMessage);
152 let mui = UserService.Instance.myUserInfo;
154 let luv = mui.local_user_view;
157 personBlocks: mui.person_blocks,
158 communityBlocks: mui.community_blocks,
159 saveUserSettingsForm: {
160 ...this.state.saveUserSettingsForm,
161 show_nsfw: luv.local_user.show_nsfw,
162 theme: luv.local_user.theme ? luv.local_user.theme : "browser",
163 default_sort_type: luv.local_user.default_sort_type,
164 default_listing_type: luv.local_user.default_listing_type,
165 interface_language: luv.local_user.interface_language,
166 discussion_languages: mui.discussion_languages,
167 avatar: luv.person.avatar,
168 banner: luv.person.banner,
169 display_name: luv.person.display_name,
170 show_avatars: luv.local_user.show_avatars,
171 bot_account: luv.person.bot_account,
172 show_bot_accounts: luv.local_user.show_bot_accounts,
173 show_scores: luv.local_user.show_scores,
174 show_read_posts: luv.local_user.show_read_posts,
175 show_new_post_notifs: luv.local_user.show_new_post_notifs,
176 email: luv.local_user.email,
178 send_notifications_to_email:
179 luv.local_user.send_notifications_to_email,
180 matrix_user_id: luv.person.matrix_user_id,
186 async componentDidMount() {
188 this.setState({ themeList: await fetchThemeList() });
191 componentWillUnmount() {
192 this.subscription?.unsubscribe();
195 get documentTitle(): string {
196 return i18n.t("settings");
201 <div className="container-lg">
204 title={this.documentTitle}
205 path={this.context.router.route.match.url}
206 description={this.documentTitle}
207 image={this.state.saveUserSettingsForm.avatar}
209 <ul className="nav nav-tabs mb-2">
210 <li className="nav-item">
212 className={`nav-link btn ${
213 this.state.currentTab == "settings" && "active"
216 { ctx: this, tab: "settings" },
223 <li className="nav-item">
225 className={`nav-link btn ${
226 this.state.currentTab == "blocks" && "active"
229 { ctx: this, tab: "blocks" },
237 {this.state.currentTab == "settings" && this.userSettings()}
238 {this.state.currentTab == "blocks" && this.blockCards()}
246 <div className="row">
247 <div className="col-12 col-md-6">
248 <div className="card border-secondary mb-3">
249 <div className="card-body">{this.saveUserSettingsHtmlForm()}</div>
252 <div className="col-12 col-md-6">
253 <div className="card border-secondary mb-3">
254 <div className="card-body">{this.changePasswordHtmlForm()}</div>
263 <div className="row">
264 <div className="col-12 col-md-6">
265 <div className="card border-secondary mb-3">
266 <div className="card-body">{this.blockUserCard()}</div>
269 <div className="col-12 col-md-6">
270 <div className="card border-secondary mb-3">
271 <div className="card-body">{this.blockCommunityCard()}</div>
278 changePasswordHtmlForm() {
281 <h5>{i18n.t("change_password")}</h5>
282 <form onSubmit={linkEvent(this, this.handleChangePasswordSubmit)}>
283 <div className="form-group row">
284 <label className="col-sm-5 col-form-label" htmlFor="user-password">
285 {i18n.t("new_password")}
287 <div className="col-sm-7">
291 className="form-control"
292 value={this.state.changePasswordForm.new_password}
293 autoComplete="new-password"
295 onInput={linkEvent(this, this.handleNewPasswordChange)}
299 <div className="form-group row">
301 className="col-sm-5 col-form-label"
302 htmlFor="user-verify-password"
304 {i18n.t("verify_password")}
306 <div className="col-sm-7">
309 id="user-verify-password"
310 className="form-control"
311 value={this.state.changePasswordForm.new_password_verify}
312 autoComplete="new-password"
314 onInput={linkEvent(this, this.handleNewPasswordVerifyChange)}
318 <div className="form-group row">
320 className="col-sm-5 col-form-label"
321 htmlFor="user-old-password"
323 {i18n.t("old_password")}
325 <div className="col-sm-7">
328 id="user-old-password"
329 className="form-control"
330 value={this.state.changePasswordForm.old_password}
331 autoComplete="new-password"
333 onInput={linkEvent(this, this.handleOldPasswordChange)}
337 <div className="form-group">
338 <button type="submit" className="btn btn-block btn-secondary mr-4">
339 {this.state.changePasswordLoading ? (
342 capitalizeFirstLetter(i18n.t("save"))
354 {this.blockUserForm()}
355 {this.blockedUsersList()}
363 <h5>{i18n.t("blocked_users")}</h5>
364 <ul className="list-unstyled mb-0">
365 {this.state.personBlocks.map(pb => (
366 <li key={pb.target.id}>
368 <PersonListing person={pb.target} />
370 className="btn btn-sm"
372 { ctx: this, recipientId: pb.target.id },
373 this.handleUnblockPerson
375 data-tippy-content={i18n.t("unblock_user")}
377 <Icon icon="x" classes="icon-inline" />
388 let blockPerson = this.state.blockPerson;
390 <div className="form-group row">
392 className="col-md-4 col-form-label"
393 htmlFor="block-person-filter"
395 {i18n.t("block_user")}
397 <div className="col-md-8">
399 className="form-control"
400 id="block-person-filter"
401 value={blockPerson?.person.id ?? 0}
403 <option value="0">—</option>
405 <option value={blockPerson.person.id}>
406 {personSelectName(blockPerson)}
415 blockCommunityCard() {
418 {this.blockCommunityForm()}
419 {this.blockedCommunitiesList()}
424 blockedCommunitiesList() {
427 <h5>{i18n.t("blocked_communities")}</h5>
428 <ul className="list-unstyled mb-0">
429 {this.state.communityBlocks.map(cb => (
430 <li key={cb.community.id}>
432 <CommunityLink community={cb.community} />
434 className="btn btn-sm"
436 { ctx: this, communityId: cb.community.id },
437 this.handleUnblockCommunity
439 data-tippy-content={i18n.t("unblock_community")}
441 <Icon icon="x" classes="icon-inline" />
451 blockCommunityForm() {
453 <div className="form-group row">
455 className="col-md-4 col-form-label"
456 htmlFor="block-community-filter"
458 {i18n.t("block_community")}
460 <div className="col-md-8">
462 className="form-control"
463 id="block-community-filter"
464 value={this.state.blockCommunityId}
466 <option value="0">—</option>
467 {this.state.blockCommunity && (
468 <option value={this.state.blockCommunity.community.id}>
469 {communitySelectName(this.state.blockCommunity)}
478 saveUserSettingsHtmlForm() {
479 let selectedLangs = this.state.saveUserSettingsForm.discussion_languages;
483 <h5>{i18n.t("settings")}</h5>
484 <form onSubmit={linkEvent(this, this.handleSaveSettingsSubmit)}>
485 <div className="form-group row">
486 <label className="col-sm-5 col-form-label" htmlFor="display-name">
487 {i18n.t("display_name")}
489 <div className="col-sm-7">
493 className="form-control"
494 placeholder={i18n.t("optional")}
495 value={this.state.saveUserSettingsForm.display_name}
496 onInput={linkEvent(this, this.handleDisplayNameChange)}
497 pattern="^(?!@)(.+)$"
502 <div className="form-group row">
503 <label className="col-sm-3 col-form-label" htmlFor="user-bio">
506 <div className="col-sm-9">
508 initialContent={this.state.saveUserSettingsForm.bio}
509 onContentChange={this.handleBioChange}
511 hideNavigationWarnings
512 allLanguages={this.state.siteRes.all_languages}
513 siteLanguages={this.state.siteRes.discussion_languages}
517 <div className="form-group row">
518 <label className="col-sm-3 col-form-label" htmlFor="user-email">
521 <div className="col-sm-9">
525 className="form-control"
526 placeholder={i18n.t("optional")}
527 value={this.state.saveUserSettingsForm.email}
528 onInput={linkEvent(this, this.handleEmailChange)}
533 <div className="form-group row">
534 <label className="col-sm-5 col-form-label" htmlFor="matrix-user-id">
535 <a href={elementUrl} rel={relTags}>
536 {i18n.t("matrix_user_id")}
539 <div className="col-sm-7">
543 className="form-control"
544 placeholder="@user:example.com"
545 value={this.state.saveUserSettingsForm.matrix_user_id}
546 onInput={linkEvent(this, this.handleMatrixUserIdChange)}
547 pattern="^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
551 <div className="form-group row">
552 <label className="col-sm-3">{i18n.t("avatar")}</label>
553 <div className="col-sm-9">
555 uploadTitle={i18n.t("upload_avatar")}
556 imageSrc={this.state.saveUserSettingsForm.avatar}
557 onUpload={this.handleAvatarUpload}
558 onRemove={this.handleAvatarRemove}
563 <div className="form-group row">
564 <label className="col-sm-3">{i18n.t("banner")}</label>
565 <div className="col-sm-9">
567 uploadTitle={i18n.t("upload_banner")}
568 imageSrc={this.state.saveUserSettingsForm.banner}
569 onUpload={this.handleBannerUpload}
570 onRemove={this.handleBannerRemove}
574 <div className="form-group row">
575 <label className="col-sm-3" htmlFor="user-language">
576 {i18n.t("interface_language")}
578 <div className="col-sm-9">
581 value={this.state.saveUserSettingsForm.interface_language}
582 onChange={linkEvent(this, this.handleInterfaceLangChange)}
583 className="custom-select w-auto"
585 <option disabled aria-hidden="true">
586 {i18n.t("interface_language")}
588 <option value="browser">{i18n.t("browser_default")}</option>
589 <option disabled aria-hidden="true">
593 .sort((a, b) => a.code.localeCompare(b.code))
595 <option key={lang.code} value={lang.code}>
603 allLanguages={this.state.siteRes.all_languages}
604 siteLanguages={this.state.siteRes.discussion_languages}
605 selectedLanguageIds={selectedLangs}
608 onChange={this.handleDiscussionLanguageChange}
610 <div className="form-group row">
611 <label className="col-sm-3" htmlFor="user-theme">
614 <div className="col-sm-9">
617 value={this.state.saveUserSettingsForm.theme}
618 onChange={linkEvent(this, this.handleThemeChange)}
619 className="custom-select w-auto"
621 <option disabled aria-hidden="true">
624 <option value="browser">{i18n.t("browser_default")}</option>
625 {this.state.themeList.map(theme => (
626 <option key={theme} value={theme}>
633 <form className="form-group row">
634 <label className="col-sm-3">{i18n.t("type")}</label>
635 <div className="col-sm-9">
638 Object.values(ListingType)[
639 this.state.saveUserSettingsForm.default_listing_type ?? 1
642 showLocal={showLocal(this.isoData)}
644 onChange={this.handleListingTypeChange}
648 <form className="form-group row">
649 <label className="col-sm-3">{i18n.t("sort_type")}</label>
650 <div className="col-sm-9">
653 Object.values(SortType)[
654 this.state.saveUserSettingsForm.default_sort_type ?? 0
657 onChange={this.handleSortTypeChange}
661 {enableNsfw(this.state.siteRes) && (
662 <div className="form-group">
663 <div className="form-check">
665 className="form-check-input"
668 checked={this.state.saveUserSettingsForm.show_nsfw}
669 onChange={linkEvent(this, this.handleShowNsfwChange)}
671 <label className="form-check-label" htmlFor="user-show-nsfw">
672 {i18n.t("show_nsfw")}
677 <div className="form-group">
678 <div className="form-check">
680 className="form-check-input"
681 id="user-show-scores"
683 checked={this.state.saveUserSettingsForm.show_scores}
684 onChange={linkEvent(this, this.handleShowScoresChange)}
686 <label className="form-check-label" htmlFor="user-show-scores">
687 {i18n.t("show_scores")}
691 <div className="form-group">
692 <div className="form-check">
694 className="form-check-input"
695 id="user-show-avatars"
697 checked={this.state.saveUserSettingsForm.show_avatars}
698 onChange={linkEvent(this, this.handleShowAvatarsChange)}
700 <label className="form-check-label" htmlFor="user-show-avatars">
701 {i18n.t("show_avatars")}
705 <div className="form-group">
706 <div className="form-check">
708 className="form-check-input"
709 id="user-bot-account"
711 checked={this.state.saveUserSettingsForm.bot_account}
712 onChange={linkEvent(this, this.handleBotAccount)}
714 <label className="form-check-label" htmlFor="user-bot-account">
715 {i18n.t("bot_account")}
719 <div className="form-group">
720 <div className="form-check">
722 className="form-check-input"
723 id="user-show-bot-accounts"
725 checked={this.state.saveUserSettingsForm.show_bot_accounts}
726 onChange={linkEvent(this, this.handleShowBotAccounts)}
729 className="form-check-label"
730 htmlFor="user-show-bot-accounts"
732 {i18n.t("show_bot_accounts")}
736 <div className="form-group">
737 <div className="form-check">
739 className="form-check-input"
740 id="user-show-read-posts"
742 checked={this.state.saveUserSettingsForm.show_read_posts}
743 onChange={linkEvent(this, this.handleReadPosts)}
746 className="form-check-label"
747 htmlFor="user-show-read-posts"
749 {i18n.t("show_read_posts")}
753 <div className="form-group">
754 <div className="form-check">
756 className="form-check-input"
757 id="user-show-new-post-notifs"
759 checked={this.state.saveUserSettingsForm.show_new_post_notifs}
760 onChange={linkEvent(this, this.handleShowNewPostNotifs)}
763 className="form-check-label"
764 htmlFor="user-show-new-post-notifs"
766 {i18n.t("show_new_post_notifs")}
770 <div className="form-group">
771 <div className="form-check">
773 className="form-check-input"
774 id="user-send-notifications-to-email"
776 disabled={!this.state.saveUserSettingsForm.email}
778 this.state.saveUserSettingsForm.send_notifications_to_email
782 this.handleSendNotificationsToEmailChange
786 className="form-check-label"
787 htmlFor="user-send-notifications-to-email"
789 {i18n.t("send_notifications_to_email")}
794 <div className="form-group">
795 <button type="submit" className="btn btn-block btn-secondary mr-4">
796 {this.state.saveUserSettingsLoading ? (
799 capitalizeFirstLetter(i18n.t("save"))
804 <div className="form-group">
806 className="btn btn-block btn-danger"
809 this.handleDeleteAccountShowConfirmToggle
812 {i18n.t("delete_account")}
814 {this.state.deleteAccountShowConfirm && (
816 <div className="my-2 alert alert-danger" role="alert">
817 {i18n.t("delete_account_confirm")}
821 value={this.state.deleteAccountForm.password}
822 autoComplete="new-password"
826 this.handleDeleteAccountPasswordChange
828 className="form-control my-2"
831 className="btn btn-danger mr-4"
832 disabled={!this.state.deleteAccountForm.password}
833 onClick={linkEvent(this, this.handleDeleteAccount)}
835 {this.state.deleteAccountLoading ? (
838 capitalizeFirstLetter(i18n.t("delete"))
842 className="btn btn-secondary"
845 this.handleDeleteAccountShowConfirmToggle
860 UserService.Instance.myUserInfo?.local_user_view.local_user.totp_2fa_url;
865 <div className="form-group">
866 <div className="form-check">
868 className="form-check-input"
869 id="user-generate-totp"
871 checked={this.state.saveUserSettingsForm.generate_totp_2fa}
872 onChange={linkEvent(this, this.handleGenerateTotp)}
874 <label className="form-check-label" htmlFor="user-generate-totp">
875 {i18n.t("set_up_two_factor")}
884 <a className="btn btn-secondary mb-2" href={totpUrl}>
885 {i18n.t("two_factor_link")}
888 <div className="form-group">
889 <div className="form-check">
891 className="form-check-input"
892 id="user-remove-totp"
895 this.state.saveUserSettingsForm.generate_totp_2fa == false
897 onChange={linkEvent(this, this.handleRemoveTotp)}
899 <label className="form-check-label" htmlFor="user-remove-totp">
900 {i18n.t("remove_two_factor")}
910 setupBlockPersonChoices() {
912 let selectId: any = document.getElementById("block-person-filter");
914 this.blockPersonChoices = new Choices(selectId, choicesConfig);
915 this.blockPersonChoices.passedElement.element.addEventListener(
918 this.handleBlockPerson(Number(e.detail.choice.value));
922 this.blockPersonChoices.passedElement.element.addEventListener(
924 debounce(async (e: any) => {
926 let persons = (await fetchUsers(e.detail.value)).users;
927 let choices = persons.map(pvs => personToChoice(pvs));
928 this.blockPersonChoices.setChoices(
944 setupBlockCommunityChoices() {
946 let selectId: any = document.getElementById("block-community-filter");
948 this.blockCommunityChoices = new Choices(selectId, choicesConfig);
949 this.blockCommunityChoices.passedElement.element.addEventListener(
952 this.handleBlockCommunity(Number(e.detail.choice.value));
956 this.blockCommunityChoices.passedElement.element.addEventListener(
958 debounce(async (e: any) => {
960 let communities = (await fetchCommunities(e.detail.value))
962 let choices = communities.map(cv => communityToChoice(cv));
963 this.blockCommunityChoices.setChoices(
979 handleBlockPerson(personId: number) {
981 if (auth && personId != 0) {
982 let blockUserForm: BlockPerson = {
987 WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
991 handleUnblockPerson(i: { ctx: Settings; recipientId: number }) {
994 let blockUserForm: BlockPerson = {
995 person_id: i.recipientId,
999 WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
1003 handleBlockCommunity(community_id: number) {
1004 let auth = myAuth();
1005 if (auth && community_id != 0) {
1006 let blockCommunityForm: BlockCommunity = {
1011 WebSocketService.Instance.send(
1012 wsClient.blockCommunity(blockCommunityForm)
1017 handleUnblockCommunity(i: { ctx: Settings; communityId: number }) {
1018 let auth = myAuth();
1020 let blockCommunityForm: BlockCommunity = {
1021 community_id: i.communityId,
1025 WebSocketService.Instance.send(
1026 wsClient.blockCommunity(blockCommunityForm)
1031 handleShowNsfwChange(i: Settings, event: any) {
1032 i.state.saveUserSettingsForm.show_nsfw = event.target.checked;
1033 i.setState(i.state);
1036 handleShowAvatarsChange(i: Settings, event: any) {
1037 i.state.saveUserSettingsForm.show_avatars = event.target.checked;
1038 let mui = UserService.Instance.myUserInfo;
1040 mui.local_user_view.local_user.show_avatars = event.target.checked;
1042 i.setState(i.state);
1045 handleBotAccount(i: Settings, event: any) {
1046 i.state.saveUserSettingsForm.bot_account = event.target.checked;
1047 i.setState(i.state);
1050 handleShowBotAccounts(i: Settings, event: any) {
1051 i.state.saveUserSettingsForm.show_bot_accounts = event.target.checked;
1052 i.setState(i.state);
1055 handleReadPosts(i: Settings, event: any) {
1056 i.state.saveUserSettingsForm.show_read_posts = event.target.checked;
1057 i.setState(i.state);
1060 handleShowNewPostNotifs(i: Settings, event: any) {
1061 i.state.saveUserSettingsForm.show_new_post_notifs = event.target.checked;
1062 i.setState(i.state);
1065 handleShowScoresChange(i: Settings, event: any) {
1066 i.state.saveUserSettingsForm.show_scores = event.target.checked;
1067 let mui = UserService.Instance.myUserInfo;
1069 mui.local_user_view.local_user.show_scores = event.target.checked;
1071 i.setState(i.state);
1074 handleGenerateTotp(i: Settings, event: any) {
1075 // Coerce false to undefined here, so it won't generate it.
1076 let checked: boolean | undefined = event.target.checked || undefined;
1078 toast(i18n.t("two_factor_setup_instructions"));
1080 i.state.saveUserSettingsForm.generate_totp_2fa = checked;
1081 i.setState(i.state);
1084 handleRemoveTotp(i: Settings, event: any) {
1085 // Coerce true to undefined here, so it won't generate it.
1086 let checked: boolean | undefined = !event.target.checked && undefined;
1087 i.state.saveUserSettingsForm.generate_totp_2fa = checked;
1088 i.setState(i.state);
1091 handleSendNotificationsToEmailChange(i: Settings, event: any) {
1092 i.state.saveUserSettingsForm.send_notifications_to_email =
1093 event.target.checked;
1094 i.setState(i.state);
1097 handleThemeChange(i: Settings, event: any) {
1098 i.state.saveUserSettingsForm.theme = event.target.value;
1099 setTheme(event.target.value, true);
1100 i.setState(i.state);
1103 handleInterfaceLangChange(i: Settings, event: any) {
1104 i.state.saveUserSettingsForm.interface_language = event.target.value;
1105 i18n.changeLanguage(
1106 getLanguages(i.state.saveUserSettingsForm.interface_language).at(0)
1108 i.setState(i.state);
1111 handleDiscussionLanguageChange(val: number[]) {
1113 s => ((s.saveUserSettingsForm.discussion_languages = val), s)
1117 handleSortTypeChange(val: SortType) {
1120 (s.saveUserSettingsForm.default_sort_type =
1121 Object.keys(SortType).indexOf(val)),
1127 handleListingTypeChange(val: ListingType) {
1130 (s.saveUserSettingsForm.default_listing_type =
1131 Object.keys(ListingType).indexOf(val)),
1137 handleEmailChange(i: Settings, event: any) {
1138 i.state.saveUserSettingsForm.email = event.target.value;
1139 i.setState(i.state);
1142 handleBioChange(val: string) {
1143 this.setState(s => ((s.saveUserSettingsForm.bio = val), s));
1146 handleAvatarUpload(url: string) {
1147 this.setState(s => ((s.saveUserSettingsForm.avatar = url), s));
1150 handleAvatarRemove() {
1151 this.setState(s => ((s.saveUserSettingsForm.avatar = ""), s));
1154 handleBannerUpload(url: string) {
1155 this.setState(s => ((s.saveUserSettingsForm.banner = url), s));
1158 handleBannerRemove() {
1159 this.setState(s => ((s.saveUserSettingsForm.banner = ""), s));
1162 handleDisplayNameChange(i: Settings, event: any) {
1163 i.state.saveUserSettingsForm.display_name = event.target.value;
1164 i.setState(i.state);
1167 handleMatrixUserIdChange(i: Settings, event: any) {
1168 i.state.saveUserSettingsForm.matrix_user_id = event.target.value;
1169 i.setState(i.state);
1172 handleNewPasswordChange(i: Settings, event: any) {
1173 i.state.changePasswordForm.new_password = event.target.value;
1174 if (i.state.changePasswordForm.new_password == "") {
1175 i.state.changePasswordForm.new_password = undefined;
1177 i.setState(i.state);
1180 handleNewPasswordVerifyChange(i: Settings, event: any) {
1181 i.state.changePasswordForm.new_password_verify = event.target.value;
1182 if (i.state.changePasswordForm.new_password_verify == "") {
1183 i.state.changePasswordForm.new_password_verify = undefined;
1185 i.setState(i.state);
1188 handleOldPasswordChange(i: Settings, event: any) {
1189 i.state.changePasswordForm.old_password = event.target.value;
1190 if (i.state.changePasswordForm.old_password == "") {
1191 i.state.changePasswordForm.old_password = undefined;
1193 i.setState(i.state);
1196 handleSaveSettingsSubmit(i: Settings, event: any) {
1197 event.preventDefault();
1198 i.setState({ saveUserSettingsLoading: true });
1199 let auth = myAuth();
1201 let form: SaveUserSettings = { ...i.state.saveUserSettingsForm, auth };
1202 WebSocketService.Instance.send(wsClient.saveUserSettings(form));
1206 handleChangePasswordSubmit(i: Settings, event: any) {
1207 event.preventDefault();
1208 i.setState({ changePasswordLoading: true });
1209 let auth = myAuth();
1210 let pForm = i.state.changePasswordForm;
1211 let new_password = pForm.new_password;
1212 let new_password_verify = pForm.new_password_verify;
1213 let old_password = pForm.old_password;
1214 if (auth && new_password && old_password && new_password_verify) {
1215 let form: ChangePassword = {
1217 new_password_verify,
1222 WebSocketService.Instance.send(wsClient.changePassword(form));
1226 handleDeleteAccountShowConfirmToggle(i: Settings, event: any) {
1227 event.preventDefault();
1228 i.setState({ deleteAccountShowConfirm: !i.state.deleteAccountShowConfirm });
1231 handleDeleteAccountPasswordChange(i: Settings, event: any) {
1232 i.state.deleteAccountForm.password = event.target.value;
1233 i.setState(i.state);
1236 handleDeleteAccount(i: Settings, event: any) {
1237 event.preventDefault();
1238 i.setState({ deleteAccountLoading: true });
1239 let auth = myAuth();
1240 let password = i.state.deleteAccountForm.password;
1241 if (auth && password) {
1242 let form: DeleteAccount = {
1246 WebSocketService.Instance.send(wsClient.deleteAccount(form));
1250 handleSwitchTab(i: { ctx: Settings; tab: string }) {
1251 i.ctx.setState({ currentTab: i.tab });
1253 if (i.ctx.state.currentTab == "blocks") {
1254 i.ctx.setupBlockPersonChoices();
1255 i.ctx.setupBlockCommunityChoices();
1259 parseMessage(msg: any) {
1260 let op = wsUserOp(msg);
1264 saveUserSettingsLoading: false,
1265 changePasswordLoading: false,
1266 deleteAccountLoading: false,
1268 toast(i18n.t(msg.error), "danger");
1270 } else if (op == UserOperation.SaveUserSettings) {
1271 let data = wsJsonToRes<LoginResponse>(msg);
1272 UserService.Instance.login(data);
1274 this.setState({ saveUserSettingsLoading: false });
1275 toast(i18n.t("saved"));
1276 window.scrollTo(0, 0);
1277 } else if (op == UserOperation.ChangePassword) {
1278 let data = wsJsonToRes<LoginResponse>(msg);
1279 UserService.Instance.login(data);
1280 this.setState({ changePasswordLoading: false });
1281 window.scrollTo(0, 0);
1282 toast(i18n.t("password_changed"));
1283 } else if (op == UserOperation.DeleteAccount) {
1285 deleteAccountLoading: false,
1286 deleteAccountShowConfirm: false,
1288 UserService.Instance.logout();
1289 window.location.href = "/";
1290 } else if (op == UserOperation.BlockPerson) {
1291 let data = wsJsonToRes<BlockPersonResponse>(msg);
1292 updatePersonBlock(data);
1293 let mui = UserService.Instance.myUserInfo;
1295 this.setState({ personBlocks: mui.person_blocks });
1297 } else if (op == UserOperation.BlockCommunity) {
1298 let data = wsJsonToRes<BlockCommunityResponse>(msg);
1299 updateCommunityBlock(data);
1300 let mui = UserService.Instance.myUserInfo;
1302 this.setState({ communityBlocks: mui.community_blocks });