]> Untitled Git - lemmy.git/blob - ui/src/components/user.tsx
Adding some site oriented settings.
[lemmy.git] / ui / src / components / user.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
3 import { Subscription } from 'rxjs';
4 import { retryWhen, delay, take } from 'rxjs/operators';
5 import {
6   UserOperation,
7   Post,
8   Comment,
9   CommunityUser,
10   GetUserDetailsForm,
11   SortType,
12   ListingType,
13   UserDetailsResponse,
14   UserView,
15   CommentResponse,
16   UserSettingsForm,
17   LoginResponse,
18   BanUserResponse,
19   AddAdminResponse,
20   DeleteAccountForm,
21 } from '../interfaces';
22 import { WebSocketService, UserService } from '../services';
23 import {
24   msgOp,
25   fetchLimit,
26   routeSortTypeToEnum,
27   capitalizeFirstLetter,
28   themes,
29   setTheme,
30   languages,
31 } from '../utils';
32 import { PostListing } from './post-listing';
33 import { SortSelect } from './sort-select';
34 import { ListingTypeSelect } from './listing-type-select';
35 import { CommentNodes } from './comment-nodes';
36 import { MomentTime } from './moment-time';
37 import { i18n } from '../i18next';
38 import { T } from 'inferno-i18next';
39
40 enum View {
41   Overview,
42   Comments,
43   Posts,
44   Saved,
45 }
46
47 interface UserState {
48   user: UserView;
49   user_id: number;
50   username: string;
51   follows: Array<CommunityUser>;
52   moderates: Array<CommunityUser>;
53   comments: Array<Comment>;
54   posts: Array<Post>;
55   saved?: Array<Post>;
56   admins: Array<UserView>;
57   view: View;
58   sort: SortType;
59   page: number;
60   loading: boolean;
61   userSettingsForm: UserSettingsForm;
62   userSettingsLoading: boolean;
63   deleteAccountLoading: boolean;
64   deleteAccountShowConfirm: boolean;
65   deleteAccountForm: DeleteAccountForm;
66 }
67
68 export class User extends Component<any, UserState> {
69   private subscription: Subscription;
70   private emptyState: UserState = {
71     user: {
72       id: null,
73       name: null,
74       fedi_name: null,
75       published: null,
76       number_of_posts: null,
77       post_score: null,
78       number_of_comments: null,
79       comment_score: null,
80       banned: null,
81     },
82     user_id: null,
83     username: null,
84     follows: [],
85     moderates: [],
86     comments: [],
87     posts: [],
88     admins: [],
89     loading: true,
90     view: this.getViewFromProps(this.props),
91     sort: this.getSortTypeFromProps(this.props),
92     page: this.getPageFromProps(this.props),
93     userSettingsForm: {
94       show_nsfw: null,
95       theme: null,
96       default_sort_type: null,
97       default_listing_type: null,
98       lang: null,
99       auth: null,
100     },
101     userSettingsLoading: null,
102     deleteAccountLoading: null,
103     deleteAccountShowConfirm: false,
104     deleteAccountForm: {
105       password: null,
106     },
107   };
108
109   constructor(props: any, context: any) {
110     super(props, context);
111
112     this.state = this.emptyState;
113     this.handleSortChange = this.handleSortChange.bind(this);
114     this.handleUserSettingsSortTypeChange = this.handleUserSettingsSortTypeChange.bind(
115       this
116     );
117     this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
118       this
119     );
120
121     this.state.user_id = Number(this.props.match.params.id);
122     this.state.username = this.props.match.params.username;
123
124     this.subscription = WebSocketService.Instance.subject
125       .pipe(
126         retryWhen(errors =>
127           errors.pipe(
128             delay(3000),
129             take(10)
130           )
131         )
132       )
133       .subscribe(
134         msg => this.parseMessage(msg),
135         err => console.error(err),
136         () => console.log('complete')
137       );
138
139     this.refetch();
140   }
141
142   get isCurrentUser() {
143     return (
144       UserService.Instance.user &&
145       UserService.Instance.user.id == this.state.user.id
146     );
147   }
148
149   getViewFromProps(props: any): View {
150     return props.match.params.view
151       ? View[capitalizeFirstLetter(props.match.params.view)]
152       : View.Overview;
153   }
154
155   getSortTypeFromProps(props: any): SortType {
156     return props.match.params.sort
157       ? routeSortTypeToEnum(props.match.params.sort)
158       : SortType.New;
159   }
160
161   getPageFromProps(props: any): number {
162     return props.match.params.page ? Number(props.match.params.page) : 1;
163   }
164
165   componentWillUnmount() {
166     this.subscription.unsubscribe();
167   }
168
169   // Necessary for back button for some reason
170   componentWillReceiveProps(nextProps: any) {
171     if (
172       nextProps.history.action == 'POP' ||
173       nextProps.history.action == 'PUSH'
174     ) {
175       this.state.view = this.getViewFromProps(nextProps);
176       this.state.sort = this.getSortTypeFromProps(nextProps);
177       this.state.page = this.getPageFromProps(nextProps);
178       this.setState(this.state);
179       this.refetch();
180     }
181   }
182
183   componentDidUpdate(lastProps: any, _lastState: UserState, _snapshot: any) {
184     // Necessary if you are on a post and you click another post (same route)
185     if (
186       lastProps.location.pathname.split('/')[2] !==
187       lastProps.history.location.pathname.split('/')[2]
188     ) {
189       // Couldnt get a refresh working. This does for now.
190       location.reload();
191     }
192   }
193
194   render() {
195     return (
196       <div class="container">
197         {this.state.loading ? (
198           <h5>
199             <svg class="icon icon-spinner spin">
200               <use xlinkHref="#icon-spinner"></use>
201             </svg>
202           </h5>
203         ) : (
204           <div class="row">
205             <div class="col-12 col-md-8">
206               <h5>/u/{this.state.user.name}</h5>
207               {this.selects()}
208               {this.state.view == View.Overview && this.overview()}
209               {this.state.view == View.Comments && this.comments()}
210               {this.state.view == View.Posts && this.posts()}
211               {this.state.view == View.Saved && this.overview()}
212               {this.paginator()}
213             </div>
214             <div class="col-12 col-md-4">
215               {this.userInfo()}
216               {this.isCurrentUser && this.userSettings()}
217               {this.moderates()}
218               {this.follows()}
219             </div>
220           </div>
221         )}
222       </div>
223     );
224   }
225
226   selects() {
227     return (
228       <div className="mb-2">
229         <select
230           value={this.state.view}
231           onChange={linkEvent(this, this.handleViewChange)}
232           class="custom-select custom-select-sm w-auto"
233         >
234           <option disabled>
235             <T i18nKey="view">#</T>
236           </option>
237           <option value={View.Overview}>
238             <T i18nKey="overview">#</T>
239           </option>
240           <option value={View.Comments}>
241             <T i18nKey="comments">#</T>
242           </option>
243           <option value={View.Posts}>
244             <T i18nKey="posts">#</T>
245           </option>
246           <option value={View.Saved}>
247             <T i18nKey="saved">#</T>
248           </option>
249         </select>
250         <span class="ml-2">
251           <SortSelect
252             sort={this.state.sort}
253             onChange={this.handleSortChange}
254             hideHot
255           />
256         </span>
257         <a
258           href={`/feeds/u/${this.state.username}.xml?sort=${
259             SortType[this.state.sort]
260           }`}
261           target="_blank"
262         >
263           <svg class="icon mx-2 text-muted small">
264             <use xlinkHref="#icon-rss">#</use>
265           </svg>
266         </a>
267       </div>
268     );
269   }
270
271   overview() {
272     let combined: Array<{ type_: string; data: Comment | Post }> = [];
273     let comments = this.state.comments.map(e => {
274       return { type_: 'comments', data: e };
275     });
276     let posts = this.state.posts.map(e => {
277       return { type_: 'posts', data: e };
278     });
279
280     combined.push(...comments);
281     combined.push(...posts);
282
283     // Sort it
284     if (this.state.sort == SortType.New) {
285       combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
286     } else {
287       combined.sort((a, b) => b.data.score - a.data.score);
288     }
289
290     return (
291       <div>
292         {combined.map(i => (
293           <div>
294             {i.type_ == 'posts' ? (
295               <PostListing
296                 post={i.data as Post}
297                 admins={this.state.admins}
298                 showCommunity
299                 viewOnly
300               />
301             ) : (
302               <CommentNodes
303                 nodes={[{ comment: i.data as Comment }]}
304                 admins={this.state.admins}
305                 noIndent
306               />
307             )}
308           </div>
309         ))}
310       </div>
311     );
312   }
313
314   comments() {
315     return (
316       <div>
317         {this.state.comments.map(comment => (
318           <CommentNodes
319             nodes={[{ comment: comment }]}
320             admins={this.state.admins}
321             noIndent
322           />
323         ))}
324       </div>
325     );
326   }
327
328   posts() {
329     return (
330       <div>
331         {this.state.posts.map(post => (
332           <PostListing
333             post={post}
334             admins={this.state.admins}
335             showCommunity
336             viewOnly
337           />
338         ))}
339       </div>
340     );
341   }
342
343   userInfo() {
344     let user = this.state.user;
345     return (
346       <div>
347         <div class="card border-secondary mb-3">
348           <div class="card-body">
349             <h5>
350               <ul class="list-inline mb-0">
351                 <li className="list-inline-item">{user.name}</li>
352                 {user.banned && (
353                   <li className="list-inline-item badge badge-danger">
354                     <T i18nKey="banned">#</T>
355                   </li>
356                 )}
357               </ul>
358             </h5>
359             <div>
360               {i18n.t('joined')} <MomentTime data={user} />
361             </div>
362             <div class="table-responsive">
363               <table class="table table-bordered table-sm mt-2 mb-0">
364                 <tr>
365                   <td>
366                     <T
367                       i18nKey="number_of_points"
368                       interpolation={{ count: user.post_score }}
369                     >
370                       #
371                     </T>
372                   </td>
373                   <td>
374                     <T
375                       i18nKey="number_of_posts"
376                       interpolation={{ count: user.number_of_posts }}
377                     >
378                       #
379                     </T>
380                   </td>
381                 </tr>
382                 <tr>
383                   <td>
384                     <T
385                       i18nKey="number_of_points"
386                       interpolation={{ count: user.comment_score }}
387                     >
388                       #
389                     </T>
390                   </td>
391                   <td>
392                     <T
393                       i18nKey="number_of_comments"
394                       interpolation={{ count: user.number_of_comments }}
395                     >
396                       #
397                     </T>
398                   </td>
399                 </tr>
400               </table>
401             </div>
402             {this.isCurrentUser && (
403               <button
404                 class="btn btn-block btn-secondary mt-3"
405                 onClick={linkEvent(this, this.handleLogoutClick)}
406               >
407                 <T i18nKey="logout">#</T>
408               </button>
409             )}
410           </div>
411         </div>
412       </div>
413     );
414   }
415
416   userSettings() {
417     return (
418       <div>
419         <div class="card border-secondary mb-3">
420           <div class="card-body">
421             <h5>
422               <T i18nKey="settings">#</T>
423             </h5>
424             <form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}>
425               <div class="form-group">
426                 <div class="col-12">
427                   <label>
428                     <T i18nKey="language">#</T>
429                   </label>
430                   <select
431                     value={this.state.userSettingsForm.lang}
432                     onChange={linkEvent(
433                       this,
434                       this.handleUserSettingsLangChange
435                     )}
436                     class="ml-2 custom-select custom-select-sm w-auto"
437                   >
438                     <option disabled>
439                       <T i18nKey="language">#</T>
440                     </option>
441                     <option value="browser">
442                       <T i18nKey="browser_default">#</T>
443                     </option>
444                     <option disabled>──</option>
445                     {languages.map(lang => (
446                       <option value={lang.code}>{lang.name}</option>
447                     ))}
448                   </select>
449                 </div>
450               </div>
451               <div class="form-group">
452                 <div class="col-12">
453                   <label>
454                     <T i18nKey="theme">#</T>
455                   </label>
456                   <select
457                     value={this.state.userSettingsForm.theme}
458                     onChange={linkEvent(
459                       this,
460                       this.handleUserSettingsThemeChange
461                     )}
462                     class="ml-2 custom-select custom-select-sm w-auto"
463                   >
464                     <option disabled>
465                       <T i18nKey="theme">#</T>
466                     </option>
467                     {themes.map(theme => (
468                       <option value={theme}>{theme}</option>
469                     ))}
470                   </select>
471                 </div>
472               </div>
473               <form className="form-group">
474                 <div class="col-12">
475                   <label>
476                     <T i18nKey="sort_type" class="mr-2">
477                       #
478                     </T>
479                   </label>
480                   <ListingTypeSelect
481                     type_={this.state.userSettingsForm.default_listing_type}
482                     onChange={this.handleUserSettingsListingTypeChange}
483                   />
484                 </div>
485               </form>
486               <form className="form-group">
487                 <div class="col-12">
488                   <label>
489                     <T i18nKey="type" class="mr-2">
490                       #
491                     </T>
492                   </label>
493                   <SortSelect
494                     sort={this.state.userSettingsForm.default_sort_type}
495                     onChange={this.handleUserSettingsSortTypeChange}
496                   />
497                 </div>
498               </form>
499               {WebSocketService.Instance.site.enable_nsfw && (
500                 <div class="form-group">
501                   <div class="col-12">
502                     <div class="form-check">
503                       <input
504                         class="form-check-input"
505                         type="checkbox"
506                         checked={this.state.userSettingsForm.show_nsfw}
507                         onChange={linkEvent(
508                           this,
509                           this.handleUserSettingsShowNsfwChange
510                         )}
511                       />
512                       <label class="form-check-label">
513                         <T i18nKey="show_nsfw">#</T>
514                       </label>
515                     </div>
516                   </div>
517                 </div>
518               )}
519               <div class="form-group">
520                 <div class="col-12">
521                   <button
522                     type="submit"
523                     class="btn btn-block btn-secondary mr-4"
524                   >
525                     {this.state.userSettingsLoading ? (
526                       <svg class="icon icon-spinner spin">
527                         <use xlinkHref="#icon-spinner"></use>
528                       </svg>
529                     ) : (
530                       capitalizeFirstLetter(i18n.t('save'))
531                     )}
532                   </button>
533                 </div>
534               </div>
535               <hr />
536               <div class="form-group mb-0">
537                 <div class="col-12">
538                   <button
539                     class="btn btn-block btn-danger"
540                     onClick={linkEvent(
541                       this,
542                       this.handleDeleteAccountShowConfirmToggle
543                     )}
544                   >
545                     <T i18nKey="delete_account">#</T>
546                   </button>
547                   {this.state.deleteAccountShowConfirm && (
548                     <>
549                       <div class="my-2 alert alert-danger" role="alert">
550                         <T i18nKey="delete_account_confirm">#</T>
551                       </div>
552                       <input
553                         type="password"
554                         value={this.state.deleteAccountForm.password}
555                         onInput={linkEvent(
556                           this,
557                           this.handleDeleteAccountPasswordChange
558                         )}
559                         class="form-control my-2"
560                       />
561                       <button
562                         class="btn btn-danger mr-4"
563                         disabled={!this.state.deleteAccountForm.password}
564                         onClick={linkEvent(this, this.handleDeleteAccount)}
565                       >
566                         {this.state.deleteAccountLoading ? (
567                           <svg class="icon icon-spinner spin">
568                             <use xlinkHref="#icon-spinner"></use>
569                           </svg>
570                         ) : (
571                           capitalizeFirstLetter(i18n.t('delete'))
572                         )}
573                       </button>
574                       <button
575                         class="btn btn-secondary"
576                         onClick={linkEvent(
577                           this,
578                           this.handleDeleteAccountShowConfirmToggle
579                         )}
580                       >
581                         <T i18nKey="cancel">#</T>
582                       </button>
583                     </>
584                   )}
585                 </div>
586               </div>
587             </form>
588           </div>
589         </div>
590       </div>
591     );
592   }
593
594   moderates() {
595     return (
596       <div>
597         {this.state.moderates.length > 0 && (
598           <div class="card border-secondary mb-3">
599             <div class="card-body">
600               <h5>
601                 <T i18nKey="moderates">#</T>
602               </h5>
603               <ul class="list-unstyled mb-0">
604                 {this.state.moderates.map(community => (
605                   <li>
606                     <Link to={`/c/${community.community_name}`}>
607                       {community.community_name}
608                     </Link>
609                   </li>
610                 ))}
611               </ul>
612             </div>
613           </div>
614         )}
615       </div>
616     );
617   }
618
619   follows() {
620     return (
621       <div>
622         {this.state.follows.length > 0 && (
623           <div class="card border-secondary mb-3">
624             <div class="card-body">
625               <h5>
626                 <T i18nKey="subscribed">#</T>
627               </h5>
628               <ul class="list-unstyled mb-0">
629                 {this.state.follows.map(community => (
630                   <li>
631                     <Link to={`/c/${community.community_name}`}>
632                       {community.community_name}
633                     </Link>
634                   </li>
635                 ))}
636               </ul>
637             </div>
638           </div>
639         )}
640       </div>
641     );
642   }
643
644   paginator() {
645     return (
646       <div class="my-2">
647         {this.state.page > 1 && (
648           <button
649             class="btn btn-sm btn-secondary mr-1"
650             onClick={linkEvent(this, this.prevPage)}
651           >
652             <T i18nKey="prev">#</T>
653           </button>
654         )}
655         <button
656           class="btn btn-sm btn-secondary"
657           onClick={linkEvent(this, this.nextPage)}
658         >
659           <T i18nKey="next">#</T>
660         </button>
661       </div>
662     );
663   }
664
665   updateUrl() {
666     let viewStr = View[this.state.view].toLowerCase();
667     let sortStr = SortType[this.state.sort].toLowerCase();
668     this.props.history.push(
669       `/u/${this.state.user.name}/view/${viewStr}/sort/${sortStr}/page/${this.state.page}`
670     );
671   }
672
673   nextPage(i: User) {
674     i.state.page++;
675     i.setState(i.state);
676     i.updateUrl();
677     i.refetch();
678   }
679
680   prevPage(i: User) {
681     i.state.page--;
682     i.setState(i.state);
683     i.updateUrl();
684     i.refetch();
685   }
686
687   refetch() {
688     let form: GetUserDetailsForm = {
689       user_id: this.state.user_id,
690       username: this.state.username,
691       sort: SortType[this.state.sort],
692       saved_only: this.state.view == View.Saved,
693       page: this.state.page,
694       limit: fetchLimit,
695     };
696     WebSocketService.Instance.getUserDetails(form);
697   }
698
699   handleSortChange(val: SortType) {
700     this.state.sort = val;
701     this.state.page = 1;
702     this.setState(this.state);
703     this.updateUrl();
704     this.refetch();
705   }
706
707   handleViewChange(i: User, event: any) {
708     i.state.view = Number(event.target.value);
709     i.state.page = 1;
710     i.setState(i.state);
711     i.updateUrl();
712     i.refetch();
713   }
714
715   handleUserSettingsShowNsfwChange(i: User, event: any) {
716     i.state.userSettingsForm.show_nsfw = event.target.checked;
717     i.setState(i.state);
718   }
719
720   handleUserSettingsThemeChange(i: User, event: any) {
721     i.state.userSettingsForm.theme = event.target.value;
722     setTheme(event.target.value);
723     i.setState(i.state);
724   }
725
726   handleUserSettingsLangChange(i: User, event: any) {
727     i.state.userSettingsForm.lang = event.target.value;
728     i18n.changeLanguage(i.state.userSettingsForm.lang);
729     i.setState(i.state);
730   }
731
732   handleUserSettingsSortTypeChange(val: SortType) {
733     this.state.userSettingsForm.default_sort_type = val;
734     this.setState(this.state);
735   }
736
737   handleUserSettingsListingTypeChange(val: ListingType) {
738     this.state.userSettingsForm.default_listing_type = val;
739     this.setState(this.state);
740   }
741
742   handleUserSettingsSubmit(i: User, event: any) {
743     event.preventDefault();
744     i.state.userSettingsLoading = true;
745     i.setState(i.state);
746
747     WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
748   }
749
750   handleDeleteAccountShowConfirmToggle(i: User, event: any) {
751     event.preventDefault();
752     i.state.deleteAccountShowConfirm = !i.state.deleteAccountShowConfirm;
753     i.setState(i.state);
754   }
755
756   handleDeleteAccountPasswordChange(i: User, event: any) {
757     i.state.deleteAccountForm.password = event.target.value;
758     i.setState(i.state);
759   }
760
761   handleLogoutClick(i: User) {
762     UserService.Instance.logout();
763     i.context.router.history.push('/');
764   }
765
766   handleDeleteAccount(i: User, event: any) {
767     event.preventDefault();
768     i.state.deleteAccountLoading = true;
769     i.setState(i.state);
770
771     WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
772   }
773
774   parseMessage(msg: any) {
775     console.log(msg);
776     let op: UserOperation = msgOp(msg);
777     if (msg.error) {
778       alert(i18n.t(msg.error));
779       this.state.deleteAccountLoading = false;
780       this.setState(this.state);
781       return;
782     } else if (op == UserOperation.GetUserDetails) {
783       let res: UserDetailsResponse = msg;
784       this.state.user = res.user;
785       this.state.comments = res.comments;
786       this.state.follows = res.follows;
787       this.state.moderates = res.moderates;
788       this.state.posts = res.posts;
789       this.state.admins = res.admins;
790       this.state.loading = false;
791       if (this.isCurrentUser) {
792         this.state.userSettingsForm.show_nsfw =
793           UserService.Instance.user.show_nsfw;
794         this.state.userSettingsForm.theme = UserService.Instance.user.theme
795           ? UserService.Instance.user.theme
796           : 'darkly';
797         this.state.userSettingsForm.default_sort_type =
798           UserService.Instance.user.default_sort_type;
799         this.state.userSettingsForm.default_listing_type =
800           UserService.Instance.user.default_listing_type;
801         this.state.userSettingsForm.lang = UserService.Instance.user.lang;
802       }
803       document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
804       window.scrollTo(0, 0);
805       this.setState(this.state);
806     } else if (op == UserOperation.EditComment) {
807       let res: CommentResponse = msg;
808
809       let found = this.state.comments.find(c => c.id == res.comment.id);
810       found.content = res.comment.content;
811       found.updated = res.comment.updated;
812       found.removed = res.comment.removed;
813       found.deleted = res.comment.deleted;
814       found.upvotes = res.comment.upvotes;
815       found.downvotes = res.comment.downvotes;
816       found.score = res.comment.score;
817
818       this.setState(this.state);
819     } else if (op == UserOperation.CreateComment) {
820       // let res: CommentResponse = msg;
821       alert(i18n.t('reply_sent'));
822       // this.state.comments.unshift(res.comment); // TODO do this right
823       // this.setState(this.state);
824     } else if (op == UserOperation.SaveComment) {
825       let res: CommentResponse = msg;
826       let found = this.state.comments.find(c => c.id == res.comment.id);
827       found.saved = res.comment.saved;
828       this.setState(this.state);
829     } else if (op == UserOperation.CreateCommentLike) {
830       let res: CommentResponse = msg;
831       let found: Comment = this.state.comments.find(
832         c => c.id === res.comment.id
833       );
834       found.score = res.comment.score;
835       found.upvotes = res.comment.upvotes;
836       found.downvotes = res.comment.downvotes;
837       if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote;
838       this.setState(this.state);
839     } else if (op == UserOperation.BanUser) {
840       let res: BanUserResponse = msg;
841       this.state.comments
842         .filter(c => c.creator_id == res.user.id)
843         .forEach(c => (c.banned = res.banned));
844       this.state.posts
845         .filter(c => c.creator_id == res.user.id)
846         .forEach(c => (c.banned = res.banned));
847       this.setState(this.state);
848     } else if (op == UserOperation.AddAdmin) {
849       let res: AddAdminResponse = msg;
850       this.state.admins = res.admins;
851       this.setState(this.state);
852     } else if (op == UserOperation.SaveUserSettings) {
853       this.state = this.emptyState;
854       this.state.userSettingsLoading = false;
855       this.setState(this.state);
856       let res: LoginResponse = msg;
857       UserService.Instance.login(res);
858     } else if (op == UserOperation.DeleteAccount) {
859       this.state.deleteAccountLoading = false;
860       this.state.deleteAccountShowConfirm = false;
861       this.setState(this.state);
862       this.context.router.history.push('/');
863     }
864   }
865 }