14 import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
16 capitalizeFirstLetter,
22 } from "@utils/helpers";
23 import { canMod, isAdmin, isBanned } from "@utils/roles";
24 import type { QueryParams } from "@utils/types";
25 import { RouteDataResponse } from "@utils/types";
26 import classNames from "classnames";
27 import format from "date-fns/format";
28 import parseISO from "date-fns/parseISO";
29 import { NoOptionI18nKeys } from "i18next";
30 import { Component, linkEvent } from "inferno";
31 import { Link } from "inferno-router";
32 import { RouteComponentProps } from "inferno-router/dist/Route";
37 BanFromCommunityResponse,
45 CommunityModeratorView,
58 GetPersonDetailsResponse,
61 MarkCommentReplyAsRead,
62 MarkPersonMentionAsRead,
75 } from "lemmy-js-client";
76 import { fetchLimit, relTags } from "../../config";
77 import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
78 import { mdToHtml } from "../../markdown";
79 import { FirstLoadService, I18NextService, UserService } from "../../services";
80 import { HttpService, RequestState } from "../../services/HttpService";
81 import { setupTippy } from "../../tippy";
82 import { toast } from "../../toast";
83 import { BannerIconHeader } from "../common/banner-icon-header";
84 import { HtmlTags } from "../common/html-tags";
85 import { Icon, Spinner } from "../common/icon";
86 import { MomentTime } from "../common/moment-time";
87 import { SortSelect } from "../common/sort-select";
88 import { CommunityLink } from "../community/community-link";
89 import { PersonDetails } from "./person-details";
90 import { PersonListing } from "./person-listing";
92 type ProfileData = RouteDataResponse<{
93 personResponse: GetPersonDetailsResponse;
96 interface ProfileState {
97 personRes: RequestState<GetPersonDetailsResponse>;
98 personBlocked: boolean;
100 banExpireDays?: number;
101 showBanDialog: boolean;
103 siteRes: GetSiteResponse;
104 finished: Map<CommentId, boolean | undefined>;
105 isIsomorphic: boolean;
108 interface ProfileProps {
109 view: PersonDetailsView;
114 function getProfileQueryParams() {
115 return getQueryParams<ProfileProps>({
116 view: getViewFromProps,
117 page: getPageFromString,
118 sort: getSortTypeFromQuery,
122 function getSortTypeFromQuery(sort?: string): SortType {
123 return sort ? (sort as SortType) : "New";
126 function getViewFromProps(view?: string): PersonDetailsView {
128 ? PersonDetailsView[view] ?? PersonDetailsView.Overview
129 : PersonDetailsView.Overview;
132 const getCommunitiesListing = (
133 translationKey: NoOptionI18nKeys,
134 communityViews?: { community: Community }[]
137 communityViews.length > 0 && (
138 <div className="card border-secondary mb-3">
139 <div className="card-body">
140 <h5>{I18NextService.i18n.t(translationKey)}</h5>
141 <ul className="list-unstyled mb-0">
142 {communityViews.map(({ community }) => (
143 <li key={community.id}>
144 <CommunityLink community={community} />
152 const Moderates = ({ moderates }: { moderates?: CommunityModeratorView[] }) =>
153 getCommunitiesListing("moderates", moderates);
155 const Follows = () =>
156 getCommunitiesListing("subscribed", UserService.Instance.myUserInfo?.follows);
158 export class Profile extends Component<
159 RouteComponentProps<{ username: string }>,
162 private isoData = setIsoData<ProfileData>(this.context);
163 state: ProfileState = {
164 personRes: { state: "empty" },
165 personBlocked: false,
166 siteRes: this.isoData.site_res,
167 showBanDialog: false,
173 constructor(props: RouteComponentProps<{ username: string }>, context: any) {
174 super(props, context);
176 this.handleSortChange = this.handleSortChange.bind(this);
177 this.handlePageChange = this.handlePageChange.bind(this);
179 this.handleBlockPerson = this.handleBlockPerson.bind(this);
180 this.handleUnblockPerson = this.handleUnblockPerson.bind(this);
182 this.handleCreateComment = this.handleCreateComment.bind(this);
183 this.handleEditComment = this.handleEditComment.bind(this);
184 this.handleSaveComment = this.handleSaveComment.bind(this);
185 this.handleBlockPersonAlt = this.handleBlockPersonAlt.bind(this);
186 this.handleDeleteComment = this.handleDeleteComment.bind(this);
187 this.handleRemoveComment = this.handleRemoveComment.bind(this);
188 this.handleCommentVote = this.handleCommentVote.bind(this);
189 this.handleAddModToCommunity = this.handleAddModToCommunity.bind(this);
190 this.handleAddAdmin = this.handleAddAdmin.bind(this);
191 this.handlePurgePerson = this.handlePurgePerson.bind(this);
192 this.handlePurgeComment = this.handlePurgeComment.bind(this);
193 this.handleCommentReport = this.handleCommentReport.bind(this);
194 this.handleDistinguishComment = this.handleDistinguishComment.bind(this);
195 this.handleTransferCommunity = this.handleTransferCommunity.bind(this);
196 this.handleCommentReplyRead = this.handleCommentReplyRead.bind(this);
197 this.handlePersonMentionRead = this.handlePersonMentionRead.bind(this);
198 this.handleBanFromCommunity = this.handleBanFromCommunity.bind(this);
199 this.handleBanPerson = this.handleBanPerson.bind(this);
200 this.handlePostVote = this.handlePostVote.bind(this);
201 this.handlePostEdit = this.handlePostEdit.bind(this);
202 this.handlePostReport = this.handlePostReport.bind(this);
203 this.handleLockPost = this.handleLockPost.bind(this);
204 this.handleDeletePost = this.handleDeletePost.bind(this);
205 this.handleRemovePost = this.handleRemovePost.bind(this);
206 this.handleSavePost = this.handleSavePost.bind(this);
207 this.handlePurgePost = this.handlePurgePost.bind(this);
208 this.handleFeaturePost = this.handleFeaturePost.bind(this);
209 this.handleModBanSubmit = this.handleModBanSubmit.bind(this);
211 // Only fetch the data if coming from another route
212 if (FirstLoadService.isFirstLoad) {
215 personRes: this.isoData.routeData.personResponse,
221 async componentDidMount() {
222 if (!this.state.isIsomorphic) {
223 await this.fetchUserData();
228 componentWillUnmount() {
229 saveScrollPosition(this.context);
232 async fetchUserData() {
233 const { page, sort, view } = getProfileQueryParams();
235 this.setState({ personRes: { state: "empty" } });
237 personRes: await HttpService.client.getPersonDetails({
238 username: this.props.match.params.username,
240 saved_only: view === PersonDetailsView.Saved,
246 restoreScrollPosition(this.context);
247 this.setPersonBlock();
250 get amCurrentUser() {
251 if (this.state.personRes.state === "success") {
253 UserService.Instance.myUserInfo?.local_user_view.person.id ===
254 this.state.personRes.data.person_view.person.id
262 const mui = UserService.Instance.myUserInfo;
263 const res = this.state.personRes;
265 if (mui && res.state === "success") {
267 personBlocked: mui.person_blocks.some(
268 ({ target: { id } }) => id === res.data.person_view.person.id
274 static async fetchInitialData({
277 query: { page, sort, view: urlView },
279 }: InitialFetchRequest<QueryParams<ProfileProps>>): Promise<ProfileData> {
280 const pathSplit = path.split("/");
282 const username = pathSplit[2];
283 const view = getViewFromProps(urlView);
285 const form: GetPersonDetails = {
287 sort: getSortTypeFromQuery(sort),
288 saved_only: view === PersonDetailsView.Saved,
289 page: getPageFromString(page),
295 personResponse: await client.getPersonDetails(form),
299 get documentTitle(): string {
300 const siteName = this.state.siteRes.site_view.site.name;
301 const res = this.state.personRes;
302 return res.state == "success"
303 ? `@${res.data.person_view.person.name} - ${siteName}`
308 switch (this.state.personRes.state) {
316 const siteRes = this.state.siteRes;
317 const personRes = this.state.personRes.data;
318 const { page, sort, view } = getProfileQueryParams();
321 <div className="row">
322 <div className="col-12 col-md-8">
324 title={this.documentTitle}
325 path={this.context.router.route.match.url}
326 description={personRes.person_view.person.bio}
327 image={personRes.person_view.person.avatar}
330 {this.userInfo(personRes.person_view)}
337 personRes={personRes}
338 admins={siteRes.admins}
342 finished={this.state.finished}
343 enableDownvotes={enableDownvotes(siteRes)}
344 enableNsfw={enableNsfw(siteRes)}
346 onPageChange={this.handlePageChange}
347 allLanguages={siteRes.all_languages}
348 siteLanguages={siteRes.discussion_languages}
349 // TODO all the forms here
350 onSaveComment={this.handleSaveComment}
351 onBlockPerson={this.handleBlockPersonAlt}
352 onDeleteComment={this.handleDeleteComment}
353 onRemoveComment={this.handleRemoveComment}
354 onCommentVote={this.handleCommentVote}
355 onCommentReport={this.handleCommentReport}
356 onDistinguishComment={this.handleDistinguishComment}
357 onAddModToCommunity={this.handleAddModToCommunity}
358 onAddAdmin={this.handleAddAdmin}
359 onTransferCommunity={this.handleTransferCommunity}
360 onPurgeComment={this.handlePurgeComment}
361 onPurgePerson={this.handlePurgePerson}
362 onCommentReplyRead={this.handleCommentReplyRead}
363 onPersonMentionRead={this.handlePersonMentionRead}
364 onBanPersonFromCommunity={this.handleBanFromCommunity}
365 onBanPerson={this.handleBanPerson}
366 onCreateComment={this.handleCreateComment}
367 onEditComment={this.handleEditComment}
368 onPostEdit={this.handlePostEdit}
369 onPostVote={this.handlePostVote}
370 onPostReport={this.handlePostReport}
371 onLockPost={this.handleLockPost}
372 onDeletePost={this.handleDeletePost}
373 onRemovePost={this.handleRemovePost}
374 onSavePost={this.handleSavePost}
375 onPurgePost={this.handlePurgePost}
376 onFeaturePost={this.handleFeaturePost}
380 <div className="col-12 col-md-4">
381 <Moderates moderates={personRes.moderates} />
382 {this.amCurrentUser && <Follows />}
392 <div className="person-profile container-lg">
393 {this.renderPersonRes()}
400 <div className="btn-group btn-group-toggle flex-wrap mb-2">
401 {this.getRadio(PersonDetailsView.Overview)}
402 {this.getRadio(PersonDetailsView.Comments)}
403 {this.getRadio(PersonDetailsView.Posts)}
404 {this.amCurrentUser && this.getRadio(PersonDetailsView.Saved)}
409 getRadio(view: PersonDetailsView) {
410 const { view: urlView } = getProfileQueryParams();
411 const active = view === urlView;
415 className={classNames("btn btn-outline-secondary pointer", {
421 className="btn-check"
424 onChange={linkEvent(this, this.handleViewChange)}
426 {I18NextService.i18n.t(view.toLowerCase() as NoOptionI18nKeys)}
432 const { sort } = getProfileQueryParams();
433 const { username } = this.props.match.params;
435 const profileRss = `/feeds/u/${username}.xml?sort=${sort}`;
438 <div className="mb-2">
439 <span className="me-3">{this.viewRadios}</span>
442 onChange={this.handleSortChange}
446 <a href={profileRss} rel={relTags} title="RSS">
447 <Icon icon="rss" classes="text-muted small mx-2" />
449 <link rel="alternate" type="application/atom+xml" href={profileRss} />
454 userInfo(pv: PersonView) {
464 {!isBanned(pv.person) && (
466 banner={pv.person.banner}
467 icon={pv.person.avatar}
470 <div className="mb-3">
472 <div className="mb-0 d-flex flex-wrap">
474 {pv.person.display_name && (
475 <h5 className="mb-0">{pv.person.display_name}</h5>
477 <ul className="list-inline mb-2">
478 <li className="list-inline-item">
487 {isBanned(pv.person) && (
488 <li className="list-inline-item">
490 label: I18NextService.i18n.t("banned"),
491 tooltip: I18NextService.i18n.t("banned"),
492 classes: "text-bg-danger",
497 {pv.person.deleted && (
498 <li className="list-inline-item">
500 label: I18NextService.i18n.t("deleted"),
501 tooltip: I18NextService.i18n.t("deleted"),
502 classes: "text-bg-danger",
507 {pv.person.admin && (
508 <li className="list-inline-item">
510 label: I18NextService.i18n.t("admin"),
511 tooltip: I18NextService.i18n.t("admin"),
516 {pv.person.bot_account && (
517 <li className="list-inline-item">
519 label: I18NextService.i18n
522 tooltip: I18NextService.i18n.t("bot_account"),
530 <div className="flex-grow-1 unselectable pointer mx-2"></div>
531 {!this.amCurrentUser && UserService.Instance.myUserInfo && (
534 className={`d-flex align-self-start btn btn-secondary me-2 ${
535 !pv.person.matrix_user_id && "invisible"
538 href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
540 {I18NextService.i18n.t("send_secure_message")}
544 "d-flex align-self-start btn btn-secondary me-2"
546 to={`/create_private_message/${pv.person.id}`}
548 {I18NextService.i18n.t("send_message")}
553 "d-flex align-self-start btn btn-secondary me-2"
557 this.handleUnblockPerson
560 {I18NextService.i18n.t("unblock_user")}
565 "d-flex align-self-start btn btn-secondary me-2"
569 this.handleBlockPerson
572 {I18NextService.i18n.t("block_user")}
578 {canMod(pv.person.id, undefined, admins) &&
579 !isAdmin(pv.person.id, admins) &&
581 (!isBanned(pv.person) ? (
584 "d-flex align-self-start btn btn-secondary me-2"
586 onClick={linkEvent(this, this.handleModBanShow)}
587 aria-label={I18NextService.i18n.t("ban")}
589 {capitalizeFirstLetter(I18NextService.i18n.t("ban"))}
594 "d-flex align-self-start btn btn-secondary me-2"
596 onClick={linkEvent(this, this.handleModBanSubmit)}
597 aria-label={I18NextService.i18n.t("unban")}
599 {capitalizeFirstLetter(I18NextService.i18n.t("unban"))}
604 <div className="d-flex align-items-center mb-2">
607 dangerouslySetInnerHTML={mdToHtml(pv.person.bio)}
612 <ul className="list-inline mb-2">
613 <li className="list-inline-item badge text-bg-light">
614 {I18NextService.i18n.t("number_of_posts", {
615 count: Number(pv.counts.post_count),
616 formattedCount: numToSI(pv.counts.post_count),
619 <li className="list-inline-item badge text-bg-light">
620 {I18NextService.i18n.t("number_of_comments", {
621 count: Number(pv.counts.comment_count),
622 formattedCount: numToSI(pv.counts.comment_count),
627 <div className="text-muted">
628 {I18NextService.i18n.t("joined")}{" "}
630 published={pv.person.published}
635 <div className="d-flex align-items-center text-muted mb-2">
637 <span className="ms-2">
638 {I18NextService.i18n.t("cake_day_title")}{" "}
639 {format(parseISO(pv.person.published), "PPP")}
642 {!UserService.Instance.myUserInfo && (
643 <div className="alert alert-info" role="alert">
644 {I18NextService.i18n.t("profile_not_logged_in_alert")}
654 banDialog(pv: PersonView) {
655 const { showBanDialog } = this.state;
659 <form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
660 <div className="mb-3 row col-12">
661 <label className="col-form-label" htmlFor="profile-ban-reason">
662 {I18NextService.i18n.t("reason")}
666 id="profile-ban-reason"
667 className="form-control me-2"
668 placeholder={I18NextService.i18n.t("reason")}
669 value={this.state.banReason}
670 onInput={linkEvent(this, this.handleModBanReasonChange)}
672 <label className="col-form-label" htmlFor="mod-ban-expires">
673 {I18NextService.i18n.t("expires")}
678 className="form-control me-2"
679 placeholder={I18NextService.i18n.t("number_of_days")}
680 value={this.state.banExpireDays}
681 onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
683 <div className="input-group mb-3">
684 <div className="form-check">
686 className="form-check-input"
687 id="mod-ban-remove-data"
689 checked={this.state.removeData}
690 onChange={linkEvent(this, this.handleModRemoveDataChange)}
693 className="form-check-label"
694 htmlFor="mod-ban-remove-data"
695 title={I18NextService.i18n.t("remove_content_more")}
697 {I18NextService.i18n.t("remove_content")}
702 {/* TODO hold off on expires until later */}
703 {/* <div class="mb-3 row"> */}
704 {/* <label class="col-form-label">Expires</label> */}
705 {/* <input type="date" class="form-control me-2" placeholder={I18NextService.i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
707 <div className="mb-3 row">
710 className="btn btn-secondary me-2"
711 aria-label={I18NextService.i18n.t("cancel")}
712 onClick={linkEvent(this, this.handleModBanSubmitCancel)}
714 {I18NextService.i18n.t("cancel")}
717 <div className="mb-3 row">
720 className="btn btn-secondary"
721 aria-label={I18NextService.i18n.t("ban")}
723 {I18NextService.i18n.t("ban")} {pv.person.name}
731 async updateUrl({ page, sort, view }: Partial<ProfileProps>) {
736 } = getProfileQueryParams();
738 const queryParams: QueryParams<ProfileProps> = {
739 page: (page ?? urlPage).toString(),
740 sort: sort ?? urlSort,
741 view: view ?? urlView,
744 const { username } = this.props.match.params;
746 this.props.history.push(`/u/${username}${getQueryString(queryParams)}`);
747 await this.fetchUserData();
750 handlePageChange(page: number) {
751 this.updateUrl({ page });
754 handleSortChange(sort: SortType) {
755 this.updateUrl({ sort, page: 1 });
758 handleViewChange(i: Profile, event: any) {
760 view: PersonDetailsView[event.target.value],
765 handleModBanShow(i: Profile) {
766 i.setState({ showBanDialog: true });
769 handleModBanReasonChange(i: Profile, event: any) {
770 i.setState({ banReason: event.target.value });
773 handleModBanExpireDaysChange(i: Profile, event: any) {
774 i.setState({ banExpireDays: event.target.value });
777 handleModRemoveDataChange(i: Profile, event: any) {
778 i.setState({ removeData: event.target.checked });
781 handleModBanSubmitCancel(i: Profile) {
782 i.setState({ showBanDialog: false });
785 async handleModBanSubmit(i: Profile, event: any) {
786 event.preventDefault();
787 const { removeData, banReason, banExpireDays } = i.state;
789 const personRes = i.state.personRes;
791 if (personRes.state == "success") {
792 const person = personRes.data.person_view.person;
793 const ban = !person.banned;
795 // If its an unban, restore all their data
797 i.setState({ removeData: false });
800 const res = await HttpService.client.banPerson({
801 person_id: person.id,
803 remove_data: removeData,
805 expires: futureDaysToUnixTime(banExpireDays),
806 auth: myAuthRequired(),
810 i.setState({ showBanDialog: false });
814 async toggleBlockPerson(recipientId: number, block: boolean) {
815 const res = await HttpService.client.blockPerson({
816 person_id: recipientId,
818 auth: myAuthRequired(),
820 if (res.state == "success") {
821 updatePersonBlock(res.data);
825 handleUnblockPerson(personId: number) {
826 this.toggleBlockPerson(personId, false);
829 handleBlockPerson(personId: number) {
830 this.toggleBlockPerson(personId, true);
833 async handleAddModToCommunity(form: AddModToCommunity) {
834 // TODO not sure what to do here
835 await HttpService.client.addModToCommunity(form);
838 async handlePurgePerson(form: PurgePerson) {
839 const purgePersonRes = await HttpService.client.purgePerson(form);
840 this.purgeItem(purgePersonRes);
843 async handlePurgeComment(form: PurgeComment) {
844 const purgeCommentRes = await HttpService.client.purgeComment(form);
845 this.purgeItem(purgeCommentRes);
848 async handlePurgePost(form: PurgePost) {
849 const purgeRes = await HttpService.client.purgePost(form);
850 this.purgeItem(purgeRes);
853 async handleBlockPersonAlt(form: BlockPerson) {
854 const blockPersonRes = await HttpService.client.blockPerson(form);
855 if (blockPersonRes.state === "success") {
856 updatePersonBlock(blockPersonRes.data);
860 async handleCreateComment(form: CreateComment) {
861 const createCommentRes = await HttpService.client.createComment(form);
862 this.createAndUpdateComments(createCommentRes);
864 return createCommentRes;
867 async handleEditComment(form: EditComment) {
868 const editCommentRes = await HttpService.client.editComment(form);
869 this.findAndUpdateComment(editCommentRes);
871 return editCommentRes;
874 async handleDeleteComment(form: DeleteComment) {
875 const deleteCommentRes = await HttpService.client.deleteComment(form);
876 this.findAndUpdateComment(deleteCommentRes);
879 async handleDeletePost(form: DeletePost) {
880 const deleteRes = await HttpService.client.deletePost(form);
881 this.findAndUpdatePost(deleteRes);
884 async handleRemovePost(form: RemovePost) {
885 const removeRes = await HttpService.client.removePost(form);
886 this.findAndUpdatePost(removeRes);
889 async handleRemoveComment(form: RemoveComment) {
890 const removeCommentRes = await HttpService.client.removeComment(form);
891 this.findAndUpdateComment(removeCommentRes);
894 async handleSaveComment(form: SaveComment) {
895 const saveCommentRes = await HttpService.client.saveComment(form);
896 this.findAndUpdateComment(saveCommentRes);
899 async handleSavePost(form: SavePost) {
900 const saveRes = await HttpService.client.savePost(form);
901 this.findAndUpdatePost(saveRes);
904 async handleFeaturePost(form: FeaturePost) {
905 const featureRes = await HttpService.client.featurePost(form);
906 this.findAndUpdatePost(featureRes);
909 async handleCommentVote(form: CreateCommentLike) {
910 const voteRes = await HttpService.client.likeComment(form);
911 this.findAndUpdateComment(voteRes);
914 async handlePostVote(form: CreatePostLike) {
915 const voteRes = await HttpService.client.likePost(form);
916 this.findAndUpdatePost(voteRes);
919 async handlePostEdit(form: EditPost) {
920 const res = await HttpService.client.editPost(form);
921 this.findAndUpdatePost(res);
924 async handleCommentReport(form: CreateCommentReport) {
925 const reportRes = await HttpService.client.createCommentReport(form);
926 if (reportRes.state === "success") {
927 toast(I18NextService.i18n.t("report_created"));
931 async handlePostReport(form: CreatePostReport) {
932 const reportRes = await HttpService.client.createPostReport(form);
933 if (reportRes.state === "success") {
934 toast(I18NextService.i18n.t("report_created"));
938 async handleLockPost(form: LockPost) {
939 const lockRes = await HttpService.client.lockPost(form);
940 this.findAndUpdatePost(lockRes);
943 async handleDistinguishComment(form: DistinguishComment) {
944 const distinguishRes = await HttpService.client.distinguishComment(form);
945 this.findAndUpdateComment(distinguishRes);
948 async handleAddAdmin(form: AddAdmin) {
949 const addAdminRes = await HttpService.client.addAdmin(form);
951 if (addAdminRes.state == "success") {
952 this.setState(s => ((s.siteRes.admins = addAdminRes.data.admins), s));
956 async handleTransferCommunity(form: TransferCommunity) {
957 await HttpService.client.transferCommunity(form);
958 toast(I18NextService.i18n.t("transfer_community"));
961 async handleCommentReplyRead(form: MarkCommentReplyAsRead) {
962 const readRes = await HttpService.client.markCommentReplyAsRead(form);
963 this.findAndUpdateCommentReply(readRes);
966 async handlePersonMentionRead(form: MarkPersonMentionAsRead) {
967 // TODO not sure what to do here. Maybe it is actually optional, because post doesn't need it.
968 await HttpService.client.markPersonMentionAsRead(form);
971 async handleBanFromCommunity(form: BanFromCommunity) {
972 const banRes = await HttpService.client.banFromCommunity(form);
973 this.updateBanFromCommunity(banRes);
976 async handleBanPerson(form: BanPerson) {
977 const banRes = await HttpService.client.banPerson(form);
978 this.updateBan(banRes);
981 updateBanFromCommunity(banRes: RequestState<BanFromCommunityResponse>) {
982 // Maybe not necessary
983 if (banRes.state === "success") {
985 if (s.personRes.state == "success") {
986 s.personRes.data.posts
987 .filter(c => c.creator.id === banRes.data.person_view.person.id)
989 c => (c.creator_banned_from_community = banRes.data.banned)
992 s.personRes.data.comments
993 .filter(c => c.creator.id === banRes.data.person_view.person.id)
995 c => (c.creator_banned_from_community = banRes.data.banned)
1003 updateBan(banRes: RequestState<BanPersonResponse>) {
1004 // Maybe not necessary
1005 if (banRes.state == "success") {
1006 this.setState(s => {
1007 if (s.personRes.state == "success") {
1008 s.personRes.data.posts
1009 .filter(c => c.creator.id == banRes.data.person_view.person.id)
1010 .forEach(c => (c.creator.banned = banRes.data.banned));
1011 s.personRes.data.comments
1012 .filter(c => c.creator.id == banRes.data.person_view.person.id)
1013 .forEach(c => (c.creator.banned = banRes.data.banned));
1014 s.personRes.data.person_view.person.banned = banRes.data.banned;
1021 purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
1022 if (purgeRes.state == "success") {
1023 toast(I18NextService.i18n.t("purge_success"));
1024 this.context.router.history.push(`/`);
1028 findAndUpdateComment(res: RequestState<CommentResponse>) {
1029 this.setState(s => {
1030 if (s.personRes.state == "success" && res.state == "success") {
1031 s.personRes.data.comments = editComment(
1032 res.data.comment_view,
1033 s.personRes.data.comments
1035 s.finished.set(res.data.comment_view.comment.id, true);
1041 createAndUpdateComments(res: RequestState<CommentResponse>) {
1042 this.setState(s => {
1043 if (s.personRes.state == "success" && res.state == "success") {
1044 s.personRes.data.comments.unshift(res.data.comment_view);
1045 // Set finished for the parent
1047 getCommentParentId(res.data.comment_view.comment) ?? 0,
1055 findAndUpdateCommentReply(res: RequestState<CommentReplyResponse>) {
1056 this.setState(s => {
1057 if (s.personRes.state == "success" && res.state == "success") {
1058 s.personRes.data.comments = editWith(
1059 res.data.comment_reply_view,
1060 s.personRes.data.comments
1067 findAndUpdatePost(res: RequestState<PostResponse>) {
1068 this.setState(s => {
1069 if (s.personRes.state == "success" && res.state == "success") {
1070 s.personRes.data.posts = editPost(
1072 s.personRes.data.posts