1 import { Component, linkEvent } from 'inferno';
2 import { Helmet } from 'inferno-helmet';
3 import { Link } from 'inferno-router';
4 import { Subscription } from 'rxjs';
12 WebSocketJsonResponse,
20 } from 'lemmy-js-client';
21 import { UserDetailsView } from '../interfaces';
22 import { WebSocketService, UserService } from '../services';
27 capitalizeFirstLetter,
44 createPostLikeFindRes,
48 import { UserListing } from './user-listing';
49 import { SortSelect } from './sort-select';
50 import { ListingTypeSelect } from './listing-type-select';
51 import { MomentTime } from './moment-time';
52 import { i18n } from '../i18next';
53 import moment from 'moment';
54 import { UserDetails } from './user-details';
55 import { MarkdownTextArea } from './markdown-textarea';
56 import { ImageUploadForm } from './image-upload-form';
57 import { BannerIconHeader } from './banner-icon-header';
60 userRes: UserDetailsResponse;
63 view: UserDetailsView;
67 userSettingsForm: UserSettingsForm;
68 userSettingsLoading: boolean;
69 deleteAccountLoading: boolean;
70 deleteAccountShowConfirm: boolean;
71 deleteAccountForm: DeleteAccountForm;
72 siteRes: GetSiteResponse;
76 view: UserDetailsView;
79 user_id: number | null;
89 export class User extends Component<any, UserState> {
90 private isoData = setIsoData(this.context);
91 private subscription: Subscription;
92 private emptyState: UserState = {
94 userId: getIdFromProps(this.props),
95 userName: getUsernameFromProps(this.props),
97 view: User.getViewFromProps(this.props.match.view),
98 sort: User.getSortTypeFromProps(this.props.match.sort),
99 page: User.getPageFromProps(this.props.match.page),
103 default_sort_type: null,
104 default_listing_type: null,
107 send_notifications_to_email: null,
110 preferred_username: null,
112 userSettingsLoading: null,
113 deleteAccountLoading: null,
114 deleteAccountShowConfirm: false,
118 siteRes: this.isoData.site,
121 constructor(props: any, context: any) {
122 super(props, context);
124 this.state = this.emptyState;
125 this.handleSortChange = this.handleSortChange.bind(this);
126 this.handleUserSettingsSortTypeChange = this.handleUserSettingsSortTypeChange.bind(
129 this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
132 this.handlePageChange = this.handlePageChange.bind(this);
133 this.handleUserSettingsBioChange = this.handleUserSettingsBioChange.bind(
137 this.handleAvatarUpload = this.handleAvatarUpload.bind(this);
138 this.handleAvatarRemove = this.handleAvatarRemove.bind(this);
140 this.handleBannerUpload = this.handleBannerUpload.bind(this);
141 this.handleBannerRemove = this.handleBannerRemove.bind(this);
143 this.parseMessage = this.parseMessage.bind(this);
144 this.subscription = wsSubscribe(this.parseMessage);
146 // Only fetch the data if coming from another route
147 if (this.isoData.path == this.context.router.route.match.url) {
148 this.state.userRes = this.isoData.routeData[0];
150 this.state.loading = false;
152 this.fetchUserData();
159 let form: GetUserDetailsForm = {
160 user_id: this.state.userId,
161 username: this.state.userName,
162 sort: this.state.sort,
163 saved_only: this.state.view === UserDetailsView.Saved,
164 page: this.state.page,
167 WebSocketService.Instance.getUserDetails(form);
170 get isCurrentUser() {
172 UserService.Instance.user &&
173 UserService.Instance.user.id == this.state.userRes.user.id
177 static getViewFromProps(view: string): UserDetailsView {
178 return view ? UserDetailsView[view] : UserDetailsView.Overview;
181 static getSortTypeFromProps(sort: string): SortType {
182 return sort ? routeSortTypeToEnum(sort) : SortType.New;
185 static getPageFromProps(page: number): number {
186 return page ? Number(page) : 1;
189 static fetchInitialData(auth: string, path: string): Promise<any>[] {
190 let pathSplit = path.split('/');
191 let promises: Promise<any>[] = [];
193 // It can be /u/me, or /username/1
194 let idOrName = pathSplit[2];
196 let username: string;
197 if (isNaN(Number(idOrName))) {
200 user_id = Number(idOrName);
203 let view = this.getViewFromProps(pathSplit[4]);
204 let sort = this.getSortTypeFromProps(pathSplit[6]);
205 let page = this.getPageFromProps(Number(pathSplit[8]));
207 let form: GetUserDetailsForm = {
209 saved_only: view === UserDetailsView.Saved,
213 this.setIdOrName(form, user_id, username);
215 promises.push(lemmyHttp.getUserDetails(form));
219 static setIdOrName(obj: any, id: number, name_: string) {
223 obj.username = name_;
227 componentWillUnmount() {
228 this.subscription.unsubscribe();
231 static getDerivedStateFromProps(props: any): UserProps {
233 view: this.getViewFromProps(props.match.params.view),
234 sort: this.getSortTypeFromProps(props.match.params.sort),
235 page: this.getPageFromProps(props.match.params.page),
236 user_id: Number(props.match.params.id) || null,
237 username: props.match.params.username,
241 componentDidUpdate(lastProps: any, _lastState: UserState, _snapshot: any) {
242 // Necessary if you are on a post and you click another post (same route)
244 lastProps.location.pathname.split('/')[2] !==
245 lastProps.history.location.pathname.split('/')[2]
247 // Couldnt get a refresh working. This does for now.
252 get documentTitle(): string {
253 if (this.state.siteRes.site.name) {
254 return `@${this.state.userName} - ${this.state.siteRes.site.name}`;
260 get favIcon(): string {
261 return this.state.siteRes.site.icon
262 ? this.state.siteRes.site.icon
268 <div class="container">
269 <Helmet title={this.documentTitle}>
277 {this.state.loading ? (
279 <svg class="icon icon-spinner spin">
280 <use xlinkHref="#icon-spinner"></use>
285 <div class="col-12 col-md-8">
290 {!this.state.loading && this.selects()}
292 userRes={this.state.userRes}
293 sort={this.state.sort}
294 page={this.state.page}
296 enableDownvotes={this.state.siteRes.site.enable_downvotes}
297 enableNsfw={this.state.siteRes.site.enable_nsfw}
298 view={this.state.view}
299 onPageChange={this.handlePageChange}
303 {!this.state.loading && (
304 <div class="col-12 col-md-4">
305 {this.isCurrentUser && this.userSettings()}
318 <div class="btn-group btn-group-toggle flex-wrap mb-2">
320 className={`btn btn-outline-secondary pointer
321 ${this.state.view == UserDetailsView.Overview && 'active'}
326 value={UserDetailsView.Overview}
327 checked={this.state.view === UserDetailsView.Overview}
328 onChange={linkEvent(this, this.handleViewChange)}
333 className={`btn btn-outline-secondary pointer
334 ${this.state.view == UserDetailsView.Comments && 'active'}
339 value={UserDetailsView.Comments}
340 checked={this.state.view == UserDetailsView.Comments}
341 onChange={linkEvent(this, this.handleViewChange)}
346 className={`btn btn-outline-secondary pointer
347 ${this.state.view == UserDetailsView.Posts && 'active'}
352 value={UserDetailsView.Posts}
353 checked={this.state.view == UserDetailsView.Posts}
354 onChange={linkEvent(this, this.handleViewChange)}
359 className={`btn btn-outline-secondary pointer
360 ${this.state.view == UserDetailsView.Saved && 'active'}
365 value={UserDetailsView.Saved}
366 checked={this.state.view == UserDetailsView.Saved}
367 onChange={linkEvent(this, this.handleViewChange)}
377 <div className="mb-2">
378 <span class="mr-3">{this.viewRadios()}</span>
380 sort={this.state.sort}
381 onChange={this.handleSortChange}
385 href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
390 <svg class="icon mx-2 text-muted small">
391 <use xlinkHref="#icon-rss">#</use>
399 let user = this.state.userRes.user;
403 <BannerIconHeader banner={user.banner} icon={user.avatar} />
406 <div class="mb-0 d-flex flex-wrap">
408 {user.preferred_username && (
409 <h5 class="mb-0">{user.preferred_username}</h5>
411 <ul class="list-inline mb-2">
412 <li className="list-inline-item">
422 <li className="list-inline-item badge badge-danger">
428 <div className="flex-grow-1 unselectable pointer mx-2"></div>
429 {this.isCurrentUser ? (
431 class="d-flex align-self-start btn btn-secondary ml-2"
432 onClick={linkEvent(this, this.handleLogoutClick)}
439 className={`d-flex align-self-start btn btn-secondary ml-2 ${
440 !user.matrix_user_id && 'invisible'
444 href={`https://matrix.to/#/${user.matrix_user_id}`}
446 {i18n.t('send_secure_message')}
449 class="d-flex align-self-start btn btn-secondary ml-2"
450 to={`/create_private_message/recipient/${user.id}`}
452 {i18n.t('send_message')}
458 <div className="d-flex align-items-center mb-2">
461 dangerouslySetInnerHTML={mdToHtml(user.bio)}
466 <ul class="list-inline mb-2">
467 <li className="list-inline-item badge badge-light">
468 {i18n.t('number_of_posts', { count: user.number_of_posts })}
470 <li className="list-inline-item badge badge-light">
471 {i18n.t('number_of_comments', {
472 count: user.number_of_comments,
477 <div class="text-muted">
478 {i18n.t('joined')} <MomentTime data={user} showAgo />
480 <div className="d-flex align-items-center text-muted mb-2">
482 <use xlinkHref="#icon-cake"></use>
484 <span className="ml-2">
485 {i18n.t('cake_day_title')}{' '}
486 {moment.utc(user.published).local().format('MMM DD, YYYY')}
498 <div class="card bg-transparent border-secondary mb-3">
499 <div class="card-body">
500 <h5>{i18n.t('settings')}</h5>
501 <form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}>
502 <div class="form-group">
503 <label>{i18n.t('avatar')}</label>
505 uploadTitle={i18n.t('upload_avatar')}
506 imageSrc={this.state.userSettingsForm.avatar}
507 onUpload={this.handleAvatarUpload}
508 onRemove={this.handleAvatarRemove}
512 <div class="form-group">
513 <label>{i18n.t('banner')}</label>
515 uploadTitle={i18n.t('upload_banner')}
516 imageSrc={this.state.userSettingsForm.banner}
517 onUpload={this.handleBannerUpload}
518 onRemove={this.handleBannerRemove}
521 <div class="form-group">
522 <label>{i18n.t('language')}</label>
524 value={this.state.userSettingsForm.lang}
525 onChange={linkEvent(this, this.handleUserSettingsLangChange)}
526 class="ml-2 custom-select w-auto"
528 <option disabled>{i18n.t('language')}</option>
529 <option value="browser">{i18n.t('browser_default')}</option>
530 <option disabled>──</option>
531 {languages.map(lang => (
532 <option value={lang.code}>{lang.name}</option>
536 <div class="form-group">
537 <label>{i18n.t('theme')}</label>
539 value={this.state.userSettingsForm.theme}
540 onChange={linkEvent(this, this.handleUserSettingsThemeChange)}
541 class="ml-2 custom-select w-auto"
543 <option disabled>{i18n.t('theme')}</option>
544 {themes.map(theme => (
545 <option value={theme}>{theme}</option>
549 <form className="form-group">
551 <div class="mr-2">{i18n.t('sort_type')}</div>
555 Object.values(ListingType)[
556 this.state.userSettingsForm.default_listing_type
559 onChange={this.handleUserSettingsListingTypeChange}
562 <form className="form-group">
564 <div class="mr-2">{i18n.t('type')}</div>
568 Object.values(SortType)[
569 this.state.userSettingsForm.default_sort_type
572 onChange={this.handleUserSettingsSortTypeChange}
575 <div class="form-group row">
576 <label class="col-lg-5 col-form-label">
577 {i18n.t('display_name')}
579 <div class="col-lg-7">
583 placeholder={i18n.t('optional')}
584 value={this.state.userSettingsForm.preferred_username}
587 this.handleUserSettingsPreferredUsernameChange
589 pattern="^(?!@)(.+)$"
595 <div class="form-group row">
596 <label class="col-lg-3 col-form-label" htmlFor="user-bio">
599 <div class="col-lg-9">
601 initialContent={this.state.userSettingsForm.bio}
602 onContentChange={this.handleUserSettingsBioChange}
604 hideNavigationWarnings
608 <div class="form-group row">
609 <label class="col-lg-3 col-form-label" htmlFor="user-email">
612 <div class="col-lg-9">
617 placeholder={i18n.t('optional')}
618 value={this.state.userSettingsForm.email}
621 this.handleUserSettingsEmailChange
627 <div class="form-group row">
628 <label class="col-lg-5 col-form-label">
629 <a href={elementUrl} target="_blank" rel="noopener">
630 {i18n.t('matrix_user_id')}
633 <div class="col-lg-7">
637 placeholder="@user:example.com"
638 value={this.state.userSettingsForm.matrix_user_id}
641 this.handleUserSettingsMatrixUserIdChange
647 <div class="form-group row">
648 <label class="col-lg-5 col-form-label" htmlFor="user-password">
649 {i18n.t('new_password')}
651 <div class="col-lg-7">
656 value={this.state.userSettingsForm.new_password}
657 autoComplete="new-password"
660 this.handleUserSettingsNewPasswordChange
665 <div class="form-group row">
667 class="col-lg-5 col-form-label"
668 htmlFor="user-verify-password"
670 {i18n.t('verify_password')}
672 <div class="col-lg-7">
675 id="user-verify-password"
677 value={this.state.userSettingsForm.new_password_verify}
678 autoComplete="new-password"
681 this.handleUserSettingsNewPasswordVerifyChange
686 <div class="form-group row">
688 class="col-lg-5 col-form-label"
689 htmlFor="user-old-password"
691 {i18n.t('old_password')}
693 <div class="col-lg-7">
696 id="user-old-password"
698 value={this.state.userSettingsForm.old_password}
699 autoComplete="new-password"
702 this.handleUserSettingsOldPasswordChange
707 {this.state.siteRes.site.enable_nsfw && (
708 <div class="form-group">
709 <div class="form-check">
711 class="form-check-input"
714 checked={this.state.userSettingsForm.show_nsfw}
717 this.handleUserSettingsShowNsfwChange
720 <label class="form-check-label" htmlFor="user-show-nsfw">
721 {i18n.t('show_nsfw')}
726 <div class="form-group">
727 <div class="form-check">
729 class="form-check-input"
730 id="user-show-avatars"
732 checked={this.state.userSettingsForm.show_avatars}
735 this.handleUserSettingsShowAvatarsChange
738 <label class="form-check-label" htmlFor="user-show-avatars">
739 {i18n.t('show_avatars')}
743 <div class="form-group">
744 <div class="form-check">
746 class="form-check-input"
747 id="user-send-notifications-to-email"
749 disabled={!this.state.userSettingsForm.email}
751 this.state.userSettingsForm.send_notifications_to_email
755 this.handleUserSettingsSendNotificationsToEmailChange
759 class="form-check-label"
760 htmlFor="user-send-notifications-to-email"
762 {i18n.t('send_notifications_to_email')}
766 <div class="form-group">
767 <button type="submit" class="btn btn-block btn-secondary mr-4">
768 {this.state.userSettingsLoading ? (
769 <svg class="icon icon-spinner spin">
770 <use xlinkHref="#icon-spinner"></use>
773 capitalizeFirstLetter(i18n.t('save'))
778 <div class="form-group mb-0">
780 class="btn btn-block btn-danger"
783 this.handleDeleteAccountShowConfirmToggle
786 {i18n.t('delete_account')}
788 {this.state.deleteAccountShowConfirm && (
790 <div class="my-2 alert alert-danger" role="alert">
791 {i18n.t('delete_account_confirm')}
795 value={this.state.deleteAccountForm.password}
796 autoComplete="new-password"
799 this.handleDeleteAccountPasswordChange
801 class="form-control my-2"
804 class="btn btn-danger mr-4"
805 disabled={!this.state.deleteAccountForm.password}
806 onClick={linkEvent(this, this.handleDeleteAccount)}
808 {this.state.deleteAccountLoading ? (
809 <svg class="icon icon-spinner spin">
810 <use xlinkHref="#icon-spinner"></use>
813 capitalizeFirstLetter(i18n.t('delete'))
817 class="btn btn-secondary"
820 this.handleDeleteAccountShowConfirmToggle
838 {this.state.userRes.moderates.length > 0 && (
839 <div class="card bg-transparent border-secondary mb-3">
840 <div class="card-body">
841 <h5>{i18n.t('moderates')}</h5>
842 <ul class="list-unstyled mb-0">
843 {this.state.userRes.moderates.map(community => (
845 <Link to={`/c/${community.community_name}`}>
846 {community.community_name}
861 {this.state.userRes.follows.length > 0 && (
862 <div class="card bg-transparent border-secondary mb-3">
863 <div class="card-body">
864 <h5>{i18n.t('subscribed')}</h5>
865 <ul class="list-unstyled mb-0">
866 {this.state.userRes.follows.map(community => (
868 <Link to={`/c/${community.community_name}`}>
869 {community.community_name}
881 updateUrl(paramUpdates: UrlParams) {
882 const page = paramUpdates.page || this.state.page;
883 const viewStr = paramUpdates.view || UserDetailsView[this.state.view];
884 const sortStr = paramUpdates.sort || this.state.sort;
885 this.props.history.push(
886 `/u/${this.state.userName}/view/${viewStr}/sort/${sortStr}/page/${page}`
890 handlePageChange(page: number) {
891 this.updateUrl({ page });
894 handleSortChange(val: SortType) {
895 this.updateUrl({ sort: val, page: 1 });
898 handleViewChange(i: User, event: any) {
900 view: UserDetailsView[Number(event.target.value)],
905 handleUserSettingsShowNsfwChange(i: User, event: any) {
906 i.state.userSettingsForm.show_nsfw = event.target.checked;
910 handleUserSettingsShowAvatarsChange(i: User, event: any) {
911 i.state.userSettingsForm.show_avatars = event.target.checked;
912 UserService.Instance.user.show_avatars = event.target.checked; // Just for instant updates
916 handleUserSettingsSendNotificationsToEmailChange(i: User, event: any) {
917 i.state.userSettingsForm.send_notifications_to_email = event.target.checked;
921 handleUserSettingsThemeChange(i: User, event: any) {
922 i.state.userSettingsForm.theme = event.target.value;
923 setTheme(event.target.value, true);
927 handleUserSettingsLangChange(i: User, event: any) {
928 i.state.userSettingsForm.lang = event.target.value;
929 i18n.changeLanguage(getLanguage(i.state.userSettingsForm.lang));
933 handleUserSettingsSortTypeChange(val: SortType) {
934 this.state.userSettingsForm.default_sort_type = Object.keys(
937 this.setState(this.state);
940 handleUserSettingsListingTypeChange(val: ListingType) {
941 this.state.userSettingsForm.default_listing_type = Object.keys(
944 this.setState(this.state);
947 handleUserSettingsEmailChange(i: User, event: any) {
948 i.state.userSettingsForm.email = event.target.value;
952 handleUserSettingsBioChange(val: string) {
953 this.state.userSettingsForm.bio = val;
954 this.setState(this.state);
957 handleAvatarUpload(url: string) {
958 this.state.userSettingsForm.avatar = url;
959 this.setState(this.state);
962 handleAvatarRemove() {
963 this.state.userSettingsForm.avatar = '';
964 this.setState(this.state);
967 handleBannerUpload(url: string) {
968 this.state.userSettingsForm.banner = url;
969 this.setState(this.state);
972 handleBannerRemove() {
973 this.state.userSettingsForm.banner = '';
974 this.setState(this.state);
977 handleUserSettingsPreferredUsernameChange(i: User, event: any) {
978 i.state.userSettingsForm.preferred_username = event.target.value;
982 handleUserSettingsMatrixUserIdChange(i: User, event: any) {
983 i.state.userSettingsForm.matrix_user_id = event.target.value;
985 i.state.userSettingsForm.matrix_user_id == '' &&
986 !i.state.userRes.user.matrix_user_id
988 i.state.userSettingsForm.matrix_user_id = undefined;
993 handleUserSettingsNewPasswordChange(i: User, event: any) {
994 i.state.userSettingsForm.new_password = event.target.value;
995 if (i.state.userSettingsForm.new_password == '') {
996 i.state.userSettingsForm.new_password = undefined;
1001 handleUserSettingsNewPasswordVerifyChange(i: User, event: any) {
1002 i.state.userSettingsForm.new_password_verify = event.target.value;
1003 if (i.state.userSettingsForm.new_password_verify == '') {
1004 i.state.userSettingsForm.new_password_verify = undefined;
1006 i.setState(i.state);
1009 handleUserSettingsOldPasswordChange(i: User, event: any) {
1010 i.state.userSettingsForm.old_password = event.target.value;
1011 if (i.state.userSettingsForm.old_password == '') {
1012 i.state.userSettingsForm.old_password = undefined;
1014 i.setState(i.state);
1017 handleUserSettingsSubmit(i: User, event: any) {
1018 event.preventDefault();
1019 i.state.userSettingsLoading = true;
1020 i.setState(i.state);
1022 WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
1025 handleDeleteAccountShowConfirmToggle(i: User, event: any) {
1026 event.preventDefault();
1027 i.state.deleteAccountShowConfirm = !i.state.deleteAccountShowConfirm;
1028 i.setState(i.state);
1031 handleDeleteAccountPasswordChange(i: User, event: any) {
1032 i.state.deleteAccountForm.password = event.target.value;
1033 i.setState(i.state);
1036 handleLogoutClick(i: User) {
1037 UserService.Instance.logout();
1038 i.context.router.history.push('/');
1041 handleDeleteAccount(i: User, event: any) {
1042 event.preventDefault();
1043 i.state.deleteAccountLoading = true;
1044 i.setState(i.state);
1046 WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
1050 if (this.isCurrentUser) {
1051 this.state.userSettingsForm.show_nsfw =
1052 UserService.Instance.user.show_nsfw;
1053 this.state.userSettingsForm.theme = UserService.Instance.user.theme
1054 ? UserService.Instance.user.theme
1056 this.state.userSettingsForm.default_sort_type =
1057 UserService.Instance.user.default_sort_type;
1058 this.state.userSettingsForm.default_listing_type =
1059 UserService.Instance.user.default_listing_type;
1060 this.state.userSettingsForm.lang = UserService.Instance.user.lang;
1061 this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
1062 this.state.userSettingsForm.banner = UserService.Instance.user.banner;
1063 this.state.userSettingsForm.preferred_username =
1064 UserService.Instance.user.preferred_username;
1065 this.state.userSettingsForm.show_avatars =
1066 UserService.Instance.user.show_avatars;
1067 this.state.userSettingsForm.email = UserService.Instance.user.email;
1068 this.state.userSettingsForm.bio = UserService.Instance.user.bio;
1069 this.state.userSettingsForm.send_notifications_to_email =
1070 UserService.Instance.user.send_notifications_to_email;
1071 this.state.userSettingsForm.matrix_user_id =
1072 UserService.Instance.user.matrix_user_id;
1076 parseMessage(msg: WebSocketJsonResponse) {
1078 const res = wsJsonToRes(msg);
1080 toast(i18n.t(msg.error), 'danger');
1081 if (msg.error == 'couldnt_find_that_username_or_email') {
1082 this.context.router.history.push('/');
1085 deleteAccountLoading: false,
1086 userSettingsLoading: false,
1089 } else if (msg.reconnect) {
1090 this.fetchUserData();
1091 } else if (res.op == UserOperation.GetUserDetails) {
1092 // Since the UserDetails contains posts/comments as well as some general user info we listen here as well
1093 // and set the parent state if it is not set or differs
1094 // TODO this might need to get abstracted
1095 const data = res.data as UserDetailsResponse;
1096 this.state.userRes = data;
1098 this.state.loading = false;
1099 this.setState(this.state);
1100 } else if (res.op == UserOperation.SaveUserSettings) {
1101 const data = res.data as LoginResponse;
1102 UserService.Instance.login(data);
1103 this.state.userRes.user.bio = this.state.userSettingsForm.bio;
1104 this.state.userRes.user.preferred_username = this.state.userSettingsForm.preferred_username;
1105 this.state.userRes.user.banner = this.state.userSettingsForm.banner;
1106 this.state.userRes.user.avatar = this.state.userSettingsForm.avatar;
1107 this.state.userSettingsLoading = false;
1108 this.setState(this.state);
1110 window.scrollTo(0, 0);
1111 } else if (res.op == UserOperation.DeleteAccount) {
1113 deleteAccountLoading: false,
1114 deleteAccountShowConfirm: false,
1116 this.context.router.history.push('/');
1117 } else if (res.op == UserOperation.AddAdmin) {
1118 const data = res.data as AddAdminResponse;
1119 this.state.siteRes.admins = data.admins;
1120 this.setState(this.state);
1121 } else if (res.op == UserOperation.CreateCommentLike) {
1122 const data = res.data as CommentResponse;
1123 createCommentLikeRes(data, this.state.userRes.comments);
1124 this.setState(this.state);
1126 res.op == UserOperation.EditComment ||
1127 res.op == UserOperation.DeleteComment ||
1128 res.op == UserOperation.RemoveComment
1130 const data = res.data as CommentResponse;
1131 editCommentRes(data, this.state.userRes.comments);
1132 this.setState(this.state);
1133 } else if (res.op == UserOperation.CreateComment) {
1134 const data = res.data as CommentResponse;
1136 UserService.Instance.user &&
1137 data.comment.creator_id == UserService.Instance.user.id
1139 toast(i18n.t('reply_sent'));
1141 } else if (res.op == UserOperation.SaveComment) {
1142 const data = res.data as CommentResponse;
1143 saveCommentRes(data, this.state.userRes.comments);
1144 this.setState(this.state);
1145 } else if (res.op == UserOperation.CreatePostLike) {
1146 const data = res.data as PostResponse;
1147 createPostLikeFindRes(data, this.state.userRes.posts);
1148 this.setState(this.state);
1149 } else if (res.op == UserOperation.BanUser) {
1150 const data = res.data as BanUserResponse;
1151 this.state.userRes.comments
1152 .filter(c => c.creator_id == data.user.id)
1153 .forEach(c => (c.banned = data.banned));
1154 this.state.userRes.posts
1155 .filter(c => c.creator_id == data.user.id)
1156 .forEach(c => (c.banned = data.banned));
1157 this.setState(this.state);