1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
3 import { Subscription } from 'rxjs';
12 GetUserDetailsResponse,
18 } from 'lemmy-js-client';
19 import { InitialFetchRequest, UserDetailsView } from '../interfaces';
20 import { WebSocketService, UserService } from '../services';
25 capitalizeFirstLetter,
41 createPostLikeFindRes,
49 import { UserListing } from './user-listing';
50 import { HtmlTags } from './html-tags';
51 import { SortSelect } from './sort-select';
52 import { ListingTypeSelect } from './listing-type-select';
53 import { MomentTime } from './moment-time';
54 import { i18n } from '../i18next';
55 import moment from 'moment';
56 import { UserDetails } from './user-details';
57 import { MarkdownTextArea } from './markdown-textarea';
58 import { ImageUploadForm } from './image-upload-form';
59 import { BannerIconHeader } from './banner-icon-header';
60 import { CommunityLink } from './community-link';
63 userRes: GetUserDetailsResponse;
66 view: UserDetailsView;
70 userSettingsForm: SaveUserSettings;
71 userSettingsLoading: boolean;
72 deleteAccountLoading: boolean;
73 deleteAccountShowConfirm: boolean;
74 deleteAccountForm: DeleteAccount;
75 siteRes: GetSiteResponse;
79 view: UserDetailsView;
82 user_id: number | null;
92 export class User extends Component<any, UserState> {
93 private isoData = setIsoData(this.context);
94 private subscription: Subscription;
95 private emptyState: UserState = {
97 userId: getIdFromProps(this.props),
98 userName: getUsernameFromProps(this.props),
100 view: User.getViewFromProps(this.props.match.view),
101 sort: User.getSortTypeFromProps(this.props.match.sort),
102 page: User.getPageFromProps(this.props.match.page),
106 default_sort_type: null,
107 default_listing_type: null,
110 send_notifications_to_email: null,
112 preferred_username: null,
113 auth: authField(false),
115 userSettingsLoading: null,
116 deleteAccountLoading: null,
117 deleteAccountShowConfirm: false,
120 auth: authField(false),
122 siteRes: this.isoData.site_res,
125 constructor(props: any, context: any) {
126 super(props, context);
128 this.state = this.emptyState;
129 this.handleSortChange = this.handleSortChange.bind(this);
130 this.handleUserSettingsSortTypeChange = this.handleUserSettingsSortTypeChange.bind(
133 this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
136 this.handlePageChange = this.handlePageChange.bind(this);
137 this.handleUserSettingsBioChange = this.handleUserSettingsBioChange.bind(
141 this.handleAvatarUpload = this.handleAvatarUpload.bind(this);
142 this.handleAvatarRemove = this.handleAvatarRemove.bind(this);
144 this.handleBannerUpload = this.handleBannerUpload.bind(this);
145 this.handleBannerRemove = this.handleBannerRemove.bind(this);
147 this.parseMessage = this.parseMessage.bind(this);
148 this.subscription = wsSubscribe(this.parseMessage);
150 // Only fetch the data if coming from another route
151 if (this.isoData.path == this.context.router.route.match.url) {
152 this.state.userRes = this.isoData.routeData[0];
154 this.state.loading = false;
156 this.fetchUserData();
163 let form: GetUserDetails = {
164 user_id: this.state.userId,
165 username: this.state.userName,
166 sort: this.state.sort,
167 saved_only: this.state.view === UserDetailsView.Saved,
168 page: this.state.page,
170 auth: authField(false),
172 WebSocketService.Instance.send(wsClient.getUserDetails(form));
175 get isCurrentUser() {
177 UserService.Instance.user &&
178 UserService.Instance.user.id == this.state.userRes.user_view.user.id
182 static getViewFromProps(view: string): UserDetailsView {
183 return view ? UserDetailsView[view] : UserDetailsView.Overview;
186 static getSortTypeFromProps(sort: string): SortType {
187 return sort ? routeSortTypeToEnum(sort) : SortType.New;
190 static getPageFromProps(page: number): number {
191 return page ? Number(page) : 1;
194 static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
195 let pathSplit = req.path.split('/');
196 let promises: Promise<any>[] = [];
198 // It can be /u/me, or /username/1
199 let idOrName = pathSplit[2];
201 let username: string;
202 if (isNaN(Number(idOrName))) {
205 user_id = Number(idOrName);
208 let view = this.getViewFromProps(pathSplit[4]);
209 let sort = this.getSortTypeFromProps(pathSplit[6]);
210 let page = this.getPageFromProps(Number(pathSplit[8]));
212 let form: GetUserDetails = {
214 saved_only: view === UserDetailsView.Saved,
218 setOptionalAuth(form, req.auth);
219 this.setIdOrName(form, user_id, username);
220 promises.push(req.client.getUserDetails(form));
224 static setIdOrName(obj: any, id: number, name_: string) {
228 obj.username = name_;
232 componentWillUnmount() {
233 this.subscription.unsubscribe();
236 static getDerivedStateFromProps(props: any): UserProps {
238 view: this.getViewFromProps(props.match.params.view),
239 sort: this.getSortTypeFromProps(props.match.params.sort),
240 page: this.getPageFromProps(props.match.params.page),
241 user_id: Number(props.match.params.id) || null,
242 username: props.match.params.username,
246 componentDidUpdate(lastProps: any, _lastState: UserState, _snapshot: any) {
247 // Necessary if you are on a post and you click another post (same route)
249 lastProps.location.pathname.split('/')[2] !==
250 lastProps.history.location.pathname.split('/')[2]
252 // Couldnt get a refresh working. This does for now.
257 get documentTitle(): string {
258 return `@${this.state.userRes.user_view.user.name} - ${this.state.siteRes.site_view.site.name}`;
261 get bioTag(): string {
262 return this.state.userRes.user_view.user.bio
263 ? previewLines(this.state.userRes.user_view.user.bio)
269 <div class="container">
270 {this.state.loading ? (
272 <svg class="icon icon-spinner spin">
273 <use xlinkHref="#icon-spinner"></use>
278 <div class="col-12 col-md-8">
281 title={this.documentTitle}
282 path={this.context.router.route.match.url}
283 description={this.bioTag}
284 image={this.state.userRes.user_view.user.avatar}
289 {!this.state.loading && this.selects()}
291 userRes={this.state.userRes}
292 admins={this.state.siteRes.admins}
293 sort={this.state.sort}
294 page={this.state.page}
297 this.state.siteRes.site_view.site.enable_downvotes
299 enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
300 view={this.state.view}
301 onPageChange={this.handlePageChange}
305 {!this.state.loading && (
306 <div class="col-12 col-md-4">
307 {this.isCurrentUser && this.userSettings()}
320 <div class="btn-group btn-group-toggle flex-wrap mb-2">
322 className={`btn btn-outline-secondary pointer
323 ${this.state.view == UserDetailsView.Overview && 'active'}
328 value={UserDetailsView.Overview}
329 checked={this.state.view === UserDetailsView.Overview}
330 onChange={linkEvent(this, this.handleViewChange)}
335 className={`btn btn-outline-secondary pointer
336 ${this.state.view == UserDetailsView.Comments && 'active'}
341 value={UserDetailsView.Comments}
342 checked={this.state.view == UserDetailsView.Comments}
343 onChange={linkEvent(this, this.handleViewChange)}
348 className={`btn btn-outline-secondary pointer
349 ${this.state.view == UserDetailsView.Posts && 'active'}
354 value={UserDetailsView.Posts}
355 checked={this.state.view == UserDetailsView.Posts}
356 onChange={linkEvent(this, this.handleViewChange)}
361 className={`btn btn-outline-secondary pointer
362 ${this.state.view == UserDetailsView.Saved && 'active'}
367 value={UserDetailsView.Saved}
368 checked={this.state.view == UserDetailsView.Saved}
369 onChange={linkEvent(this, this.handleViewChange)}
379 <div className="mb-2">
380 <span class="mr-3">{this.viewRadios()}</span>
382 sort={this.state.sort}
383 onChange={this.handleSortChange}
387 href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
392 <svg class="icon mx-2 text-muted small">
393 <use xlinkHref="#icon-rss">#</use>
401 let uv = this.state.userRes?.user_view;
405 <BannerIconHeader banner={uv.user.banner} icon={uv.user.avatar} />
408 <div class="mb-0 d-flex flex-wrap">
410 {uv.user.preferred_username && (
411 <h5 class="mb-0">{uv.user.preferred_username}</h5>
413 <ul class="list-inline mb-2">
414 <li className="list-inline-item">
424 <li className="list-inline-item badge badge-danger">
430 <div className="flex-grow-1 unselectable pointer mx-2"></div>
431 {this.isCurrentUser ? (
433 class="d-flex align-self-start btn btn-secondary mr-2"
434 onClick={linkEvent(this, this.handleLogoutClick)}
441 className={`d-flex align-self-start btn btn-secondary mr-2 ${
442 !uv.user.matrix_user_id && 'invisible'
446 href={`https://matrix.to/#/${uv.user.matrix_user_id}`}
448 {i18n.t('send_secure_message')}
451 className={'d-flex align-self-start btn btn-secondary'}
452 to={`/create_private_message/recipient/${uv.user.id}`}
454 {i18n.t('send_message')}
460 <div className="d-flex align-items-center mb-2">
463 dangerouslySetInnerHTML={mdToHtml(uv.user.bio)}
468 <ul class="list-inline mb-2">
469 <li className="list-inline-item badge badge-light">
470 {i18n.t('number_of_posts', { count: uv.counts.post_count })}
472 <li className="list-inline-item badge badge-light">
473 {i18n.t('number_of_comments', {
474 count: uv.counts.comment_count,
479 <div class="text-muted">
480 {i18n.t('joined')} <MomentTime data={uv.user} showAgo />
482 <div className="d-flex align-items-center text-muted mb-2">
484 <use xlinkHref="#icon-cake"></use>
486 <span className="ml-2">
487 {i18n.t('cake_day_title')}{' '}
488 {moment.utc(uv.user.published).local().format('MMM DD, YYYY')}
500 <div class="card border-secondary mb-3">
501 <div class="card-body">
502 <h5>{i18n.t('settings')}</h5>
503 <form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}>
504 <div class="form-group">
505 <label>{i18n.t('avatar')}</label>
507 uploadTitle={i18n.t('upload_avatar')}
508 imageSrc={this.state.userSettingsForm.avatar}
509 onUpload={this.handleAvatarUpload}
510 onRemove={this.handleAvatarRemove}
514 <div class="form-group">
515 <label>{i18n.t('banner')}</label>
517 uploadTitle={i18n.t('upload_banner')}
518 imageSrc={this.state.userSettingsForm.banner}
519 onUpload={this.handleBannerUpload}
520 onRemove={this.handleBannerRemove}
523 <div class="form-group">
524 <label>{i18n.t('language')}</label>
526 value={this.state.userSettingsForm.lang}
527 onChange={linkEvent(this, this.handleUserSettingsLangChange)}
528 class="ml-2 custom-select w-auto"
530 <option disabled>{i18n.t('language')}</option>
531 <option value="browser">{i18n.t('browser_default')}</option>
532 <option disabled>──</option>
533 {languages.map(lang => (
534 <option value={lang.code}>{lang.name}</option>
538 <div class="form-group">
539 <label>{i18n.t('theme')}</label>
541 value={this.state.userSettingsForm.theme}
542 onChange={linkEvent(this, this.handleUserSettingsThemeChange)}
543 class="ml-2 custom-select w-auto"
545 <option disabled>{i18n.t('theme')}</option>
546 <option value="browser">{i18n.t('browser_default')}</option>
547 {themes.map(theme => (
548 <option value={theme}>{theme}</option>
552 <form className="form-group">
554 <div class="mr-2">{i18n.t('sort_type')}</div>
558 Object.values(ListingType)[
559 this.state.userSettingsForm.default_listing_type
563 this.state.siteRes.federated_instances &&
564 this.state.siteRes.federated_instances.length > 0
566 onChange={this.handleUserSettingsListingTypeChange}
569 <form className="form-group">
571 <div class="mr-2">{i18n.t('type')}</div>
575 Object.values(SortType)[
576 this.state.userSettingsForm.default_sort_type
579 onChange={this.handleUserSettingsSortTypeChange}
582 <div class="form-group row">
583 <label class="col-lg-5 col-form-label">
584 {i18n.t('display_name')}
586 <div class="col-lg-7">
590 placeholder={i18n.t('optional')}
591 value={this.state.userSettingsForm.preferred_username}
594 this.handleUserSettingsPreferredUsernameChange
596 pattern="^(?!@)(.+)$"
602 <div class="form-group row">
603 <label class="col-lg-3 col-form-label" htmlFor="user-bio">
606 <div class="col-lg-9">
608 initialContent={this.state.userSettingsForm.bio}
609 onContentChange={this.handleUserSettingsBioChange}
611 hideNavigationWarnings
615 <div class="form-group row">
616 <label class="col-lg-3 col-form-label" htmlFor="user-email">
619 <div class="col-lg-9">
624 placeholder={i18n.t('optional')}
625 value={this.state.userSettingsForm.email}
628 this.handleUserSettingsEmailChange
634 <div class="form-group row">
635 <label class="col-lg-5 col-form-label">
636 <a href={elementUrl} target="_blank" rel="noopener">
637 {i18n.t('matrix_user_id')}
640 <div class="col-lg-7">
644 placeholder="@user:example.com"
645 value={this.state.userSettingsForm.matrix_user_id}
648 this.handleUserSettingsMatrixUserIdChange
654 <div class="form-group row">
655 <label class="col-lg-5 col-form-label" htmlFor="user-password">
656 {i18n.t('new_password')}
658 <div class="col-lg-7">
663 value={this.state.userSettingsForm.new_password}
664 autoComplete="new-password"
667 this.handleUserSettingsNewPasswordChange
672 <div class="form-group row">
674 class="col-lg-5 col-form-label"
675 htmlFor="user-verify-password"
677 {i18n.t('verify_password')}
679 <div class="col-lg-7">
682 id="user-verify-password"
684 value={this.state.userSettingsForm.new_password_verify}
685 autoComplete="new-password"
688 this.handleUserSettingsNewPasswordVerifyChange
693 <div class="form-group row">
695 class="col-lg-5 col-form-label"
696 htmlFor="user-old-password"
698 {i18n.t('old_password')}
700 <div class="col-lg-7">
703 id="user-old-password"
705 value={this.state.userSettingsForm.old_password}
706 autoComplete="new-password"
709 this.handleUserSettingsOldPasswordChange
714 {this.state.siteRes.site_view.site.enable_nsfw && (
715 <div class="form-group">
716 <div class="form-check">
718 class="form-check-input"
721 checked={this.state.userSettingsForm.show_nsfw}
724 this.handleUserSettingsShowNsfwChange
727 <label class="form-check-label" htmlFor="user-show-nsfw">
728 {i18n.t('show_nsfw')}
733 <div class="form-group">
734 <div class="form-check">
736 class="form-check-input"
737 id="user-show-avatars"
739 checked={this.state.userSettingsForm.show_avatars}
742 this.handleUserSettingsShowAvatarsChange
745 <label class="form-check-label" htmlFor="user-show-avatars">
746 {i18n.t('show_avatars')}
750 <div class="form-group">
751 <div class="form-check">
753 class="form-check-input"
754 id="user-send-notifications-to-email"
756 disabled={!this.state.userSettingsForm.email}
758 this.state.userSettingsForm.send_notifications_to_email
762 this.handleUserSettingsSendNotificationsToEmailChange
766 class="form-check-label"
767 htmlFor="user-send-notifications-to-email"
769 {i18n.t('send_notifications_to_email')}
773 <div class="form-group">
774 <button type="submit" class="btn btn-block btn-secondary mr-4">
775 {this.state.userSettingsLoading ? (
776 <svg class="icon icon-spinner spin">
777 <use xlinkHref="#icon-spinner"></use>
780 capitalizeFirstLetter(i18n.t('save'))
785 <div class="form-group mb-0">
787 class="btn btn-block btn-danger"
790 this.handleDeleteAccountShowConfirmToggle
793 {i18n.t('delete_account')}
795 {this.state.deleteAccountShowConfirm && (
797 <div class="my-2 alert alert-danger" role="alert">
798 {i18n.t('delete_account_confirm')}
802 value={this.state.deleteAccountForm.password}
803 autoComplete="new-password"
806 this.handleDeleteAccountPasswordChange
808 class="form-control my-2"
811 class="btn btn-danger mr-4"
812 disabled={!this.state.deleteAccountForm.password}
813 onClick={linkEvent(this, this.handleDeleteAccount)}
815 {this.state.deleteAccountLoading ? (
816 <svg class="icon icon-spinner spin">
817 <use xlinkHref="#icon-spinner"></use>
820 capitalizeFirstLetter(i18n.t('delete'))
824 class="btn btn-secondary"
827 this.handleDeleteAccountShowConfirmToggle
845 {this.state.userRes.moderates.length > 0 && (
846 <div class="card border-secondary mb-3">
847 <div class="card-body">
848 <h5>{i18n.t('moderates')}</h5>
849 <ul class="list-unstyled mb-0">
850 {this.state.userRes.moderates.map(cmv => (
852 <CommunityLink community={cmv.community} />
866 {this.state.userRes.follows.length > 0 && (
867 <div class="card border-secondary mb-3">
868 <div class="card-body">
869 <h5>{i18n.t('subscribed')}</h5>
870 <ul class="list-unstyled mb-0">
871 {this.state.userRes.follows.map(cfv => (
873 <CommunityLink community={cfv.community} />
884 updateUrl(paramUpdates: UrlParams) {
885 const page = paramUpdates.page || this.state.page;
886 const viewStr = paramUpdates.view || UserDetailsView[this.state.view];
887 const sortStr = paramUpdates.sort || this.state.sort;
888 this.props.history.push(
889 `/u/${this.state.userName}/view/${viewStr}/sort/${sortStr}/page/${page}`
891 this.state.loading = true;
892 this.setState(this.state);
893 this.fetchUserData();
896 handlePageChange(page: number) {
897 this.updateUrl({ page });
900 handleSortChange(val: SortType) {
901 this.updateUrl({ sort: val, page: 1 });
904 handleViewChange(i: User, event: any) {
906 view: UserDetailsView[Number(event.target.value)],
911 handleUserSettingsShowNsfwChange(i: User, event: any) {
912 i.state.userSettingsForm.show_nsfw = event.target.checked;
916 handleUserSettingsShowAvatarsChange(i: User, event: any) {
917 i.state.userSettingsForm.show_avatars = event.target.checked;
918 UserService.Instance.user.show_avatars = event.target.checked; // Just for instant updates
922 handleUserSettingsSendNotificationsToEmailChange(i: User, event: any) {
923 i.state.userSettingsForm.send_notifications_to_email = event.target.checked;
927 handleUserSettingsThemeChange(i: User, event: any) {
928 i.state.userSettingsForm.theme = event.target.value;
929 setTheme(event.target.value, true);
933 handleUserSettingsLangChange(i: User, event: any) {
934 i.state.userSettingsForm.lang = event.target.value;
935 i18n.changeLanguage(getLanguage(i.state.userSettingsForm.lang));
939 handleUserSettingsSortTypeChange(val: SortType) {
940 this.state.userSettingsForm.default_sort_type = Object.keys(
943 this.setState(this.state);
946 handleUserSettingsListingTypeChange(val: ListingType) {
947 this.state.userSettingsForm.default_listing_type = Object.keys(
950 this.setState(this.state);
953 handleUserSettingsEmailChange(i: User, event: any) {
954 i.state.userSettingsForm.email = event.target.value;
958 handleUserSettingsBioChange(val: string) {
959 this.state.userSettingsForm.bio = val;
960 this.setState(this.state);
963 handleAvatarUpload(url: string) {
964 this.state.userSettingsForm.avatar = url;
965 this.setState(this.state);
968 handleAvatarRemove() {
969 this.state.userSettingsForm.avatar = '';
970 this.setState(this.state);
973 handleBannerUpload(url: string) {
974 this.state.userSettingsForm.banner = url;
975 this.setState(this.state);
978 handleBannerRemove() {
979 this.state.userSettingsForm.banner = '';
980 this.setState(this.state);
983 handleUserSettingsPreferredUsernameChange(i: User, event: any) {
984 i.state.userSettingsForm.preferred_username = event.target.value;
988 handleUserSettingsMatrixUserIdChange(i: User, event: any) {
989 i.state.userSettingsForm.matrix_user_id = event.target.value;
991 i.state.userSettingsForm.matrix_user_id == '' &&
992 !i.state.userRes.user_view.user.matrix_user_id
994 i.state.userSettingsForm.matrix_user_id = undefined;
999 handleUserSettingsNewPasswordChange(i: User, event: any) {
1000 i.state.userSettingsForm.new_password = event.target.value;
1001 if (i.state.userSettingsForm.new_password == '') {
1002 i.state.userSettingsForm.new_password = undefined;
1004 i.setState(i.state);
1007 handleUserSettingsNewPasswordVerifyChange(i: User, event: any) {
1008 i.state.userSettingsForm.new_password_verify = event.target.value;
1009 if (i.state.userSettingsForm.new_password_verify == '') {
1010 i.state.userSettingsForm.new_password_verify = undefined;
1012 i.setState(i.state);
1015 handleUserSettingsOldPasswordChange(i: User, event: any) {
1016 i.state.userSettingsForm.old_password = event.target.value;
1017 if (i.state.userSettingsForm.old_password == '') {
1018 i.state.userSettingsForm.old_password = undefined;
1020 i.setState(i.state);
1023 handleUserSettingsSubmit(i: User, event: any) {
1024 event.preventDefault();
1025 i.state.userSettingsLoading = true;
1026 i.setState(i.state);
1028 WebSocketService.Instance.send(
1029 wsClient.saveUserSettings(i.state.userSettingsForm)
1033 handleDeleteAccountShowConfirmToggle(i: User, event: any) {
1034 event.preventDefault();
1035 i.state.deleteAccountShowConfirm = !i.state.deleteAccountShowConfirm;
1036 i.setState(i.state);
1039 handleDeleteAccountPasswordChange(i: User, event: any) {
1040 i.state.deleteAccountForm.password = event.target.value;
1041 i.setState(i.state);
1044 handleLogoutClick(i: User) {
1045 UserService.Instance.logout();
1046 i.context.router.history.push('/');
1049 handleDeleteAccount(i: User, event: any) {
1050 event.preventDefault();
1051 i.state.deleteAccountLoading = true;
1052 i.setState(i.state);
1054 WebSocketService.Instance.send(
1055 wsClient.deleteAccount(i.state.deleteAccountForm)
1057 i.handleLogoutClick(i);
1061 if (this.isCurrentUser) {
1062 this.state.userSettingsForm.show_nsfw =
1063 UserService.Instance.user.show_nsfw;
1064 this.state.userSettingsForm.theme = UserService.Instance.user.theme
1065 ? UserService.Instance.user.theme
1067 this.state.userSettingsForm.default_sort_type =
1068 UserService.Instance.user.default_sort_type;
1069 this.state.userSettingsForm.default_listing_type =
1070 UserService.Instance.user.default_listing_type;
1071 this.state.userSettingsForm.lang = UserService.Instance.user.lang;
1072 this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
1073 this.state.userSettingsForm.banner = UserService.Instance.user.banner;
1074 this.state.userSettingsForm.preferred_username =
1075 UserService.Instance.user.preferred_username;
1076 this.state.userSettingsForm.show_avatars =
1077 UserService.Instance.user.show_avatars;
1078 this.state.userSettingsForm.email = UserService.Instance.user.email;
1079 this.state.userSettingsForm.bio = UserService.Instance.user.bio;
1080 this.state.userSettingsForm.send_notifications_to_email =
1081 UserService.Instance.user.send_notifications_to_email;
1082 this.state.userSettingsForm.matrix_user_id =
1083 UserService.Instance.user.matrix_user_id;
1087 parseMessage(msg: any) {
1088 let op = wsUserOp(msg);
1090 toast(i18n.t(msg.error), 'danger');
1091 if (msg.error == 'couldnt_find_that_username_or_email') {
1092 this.context.router.history.push('/');
1095 deleteAccountLoading: false,
1096 userSettingsLoading: false,
1099 } else if (msg.reconnect) {
1100 this.fetchUserData();
1101 } else if (op == UserOperation.GetUserDetails) {
1102 // Since the UserDetails contains posts/comments as well as some general user info we listen here as well
1103 // and set the parent state if it is not set or differs
1104 // TODO this might need to get abstracted
1105 let data = wsJsonToRes<GetUserDetailsResponse>(msg).data;
1106 this.state.userRes = data;
1108 this.state.loading = false;
1109 this.setState(this.state);
1110 } else if (op == UserOperation.SaveUserSettings) {
1111 let data = wsJsonToRes<LoginResponse>(msg).data;
1112 UserService.Instance.login(data);
1113 this.state.userRes.user_view.user.bio = this.state.userSettingsForm.bio;
1114 this.state.userRes.user_view.user.preferred_username = this.state.userSettingsForm.preferred_username;
1115 this.state.userRes.user_view.user.banner = this.state.userSettingsForm.banner;
1116 this.state.userRes.user_view.user.avatar = this.state.userSettingsForm.avatar;
1117 this.state.userSettingsLoading = false;
1118 this.setState(this.state);
1120 window.scrollTo(0, 0);
1121 } else if (op == UserOperation.DeleteAccount) {
1123 deleteAccountLoading: false,
1124 deleteAccountShowConfirm: false,
1126 this.context.router.history.push('/');
1127 } else if (op == UserOperation.AddAdmin) {
1128 let data = wsJsonToRes<AddAdminResponse>(msg).data;
1129 this.state.siteRes.admins = data.admins;
1130 this.setState(this.state);
1131 } else if (op == UserOperation.CreateCommentLike) {
1132 let data = wsJsonToRes<CommentResponse>(msg).data;
1133 createCommentLikeRes(data.comment_view, this.state.userRes.comments);
1134 this.setState(this.state);
1136 op == UserOperation.EditComment ||
1137 op == UserOperation.DeleteComment ||
1138 op == UserOperation.RemoveComment
1140 let data = wsJsonToRes<CommentResponse>(msg).data;
1141 editCommentRes(data.comment_view, this.state.userRes.comments);
1142 this.setState(this.state);
1143 } else if (op == UserOperation.CreateComment) {
1144 let data = wsJsonToRes<CommentResponse>(msg).data;
1146 UserService.Instance.user &&
1147 data.comment_view.creator.id == UserService.Instance.user.id
1149 toast(i18n.t('reply_sent'));
1151 } else if (op == UserOperation.SaveComment) {
1152 let data = wsJsonToRes<CommentResponse>(msg).data;
1153 saveCommentRes(data.comment_view, this.state.userRes.comments);
1154 this.setState(this.state);
1156 op == UserOperation.EditPost ||
1157 op == UserOperation.DeletePost ||
1158 op == UserOperation.RemovePost ||
1159 op == UserOperation.LockPost ||
1160 op == UserOperation.StickyPost ||
1161 op == UserOperation.SavePost
1163 let data = wsJsonToRes<PostResponse>(msg).data;
1164 editPostFindRes(data.post_view, this.state.userRes.posts);
1165 this.setState(this.state);
1166 } else if (op == UserOperation.CreatePostLike) {
1167 let data = wsJsonToRes<PostResponse>(msg).data;
1168 createPostLikeFindRes(data.post_view, this.state.userRes.posts);
1169 this.setState(this.state);
1170 } else if (op == UserOperation.BanUser) {
1171 let data = wsJsonToRes<BanUserResponse>(msg).data;
1172 this.state.userRes.comments
1173 .filter(c => c.creator.id == data.user_view.user.id)
1174 .forEach(c => (c.creator.banned = data.banned));
1175 this.state.userRes.posts
1176 .filter(c => c.creator.id == data.user_view.user.id)
1177 .forEach(c => (c.creator.banned = data.banned));
1178 this.setState(this.state);