+import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
import {
AddAdminResponse,
+ BanPerson,
BanPersonResponse,
+ BlockPerson,
BlockPersonResponse,
CommentResponse,
GetPersonDetails,
GetPersonDetailsResponse,
GetSiteResponse,
PostResponse,
+ PurgeItemResponse,
SortType,
+ toUndefined,
UserOperation,
+ wsJsonToRes,
+ wsUserOp,
} from "lemmy-js-client";
import moment from "moment";
import { Subscription } from "rxjs";
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- authField,
+ auth,
+ canMod,
+ capitalizeFirstLetter,
createCommentLikeRes,
createPostLikeFindRes,
editCommentRes,
editPostFindRes,
+ enableDownvotes,
+ enableNsfw,
fetchLimit,
+ futureDaysToUnixTime,
getUsernameFromProps,
+ isAdmin,
+ isBanned,
mdToHtml,
- previewLines,
+ numToSI,
+ relTags,
restoreScrollPosition,
routeSortTypeToEnum,
saveCommentRes,
saveScrollPosition,
setIsoData,
- setOptionalAuth,
setupTippy,
toast,
updatePersonBlock,
wsClient,
- wsJsonToRes,
wsSubscribe,
- wsUserOp,
} from "../../utils";
import { BannerIconHeader } from "../common/banner-icon-header";
import { HtmlTags } from "../common/html-tags";
import { PersonListing } from "./person-listing";
interface ProfileState {
- personRes: GetPersonDetailsResponse;
+ personRes: Option<GetPersonDetailsResponse>;
userName: string;
view: PersonDetailsView;
sort: SortType;
page: number;
loading: boolean;
+ personBlocked: boolean;
+ banReason: Option<string>;
+ banExpireDays: Option<number>;
+ showBanDialog: boolean;
+ removeData: boolean;
siteRes: GetSiteResponse;
}
}
export class Profile extends Component<any, ProfileState> {
- private isoData = setIsoData(this.context);
+ private isoData = setIsoData(this.context, GetPersonDetailsResponse);
private subscription: Subscription;
private emptyState: ProfileState = {
- personRes: undefined,
+ personRes: None,
userName: getUsernameFromProps(this.props),
loading: true,
view: Profile.getViewFromProps(this.props.match.view),
sort: Profile.getSortTypeFromProps(this.props.match.sort),
page: Profile.getPageFromProps(this.props.match.page),
+ personBlocked: false,
siteRes: this.isoData.site_res,
+ showBanDialog: false,
+ banReason: null,
+ banExpireDays: null,
+ removeData: false,
};
constructor(props: any, context: any) {
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
- this.state.personRes = this.isoData.routeData[0];
- this.state.loading = false;
+ this.state = {
+ ...this.state,
+ personRes: Some(this.isoData.routeData[0] as GetPersonDetailsResponse),
+ loading: false,
+ };
} else {
this.fetchUserData();
}
-
- setupTippy();
}
fetchUserData() {
- let form: GetPersonDetails = {
- username: this.state.userName,
- sort: this.state.sort,
- saved_only: this.state.view === PersonDetailsView.Saved,
- page: this.state.page,
- limit: fetchLimit,
- auth: authField(false),
- };
+ let form = new GetPersonDetails({
+ username: Some(this.state.userName),
+ person_id: None,
+ community_id: None,
+ sort: Some(this.state.sort),
+ saved_only: Some(this.state.view === PersonDetailsView.Saved),
+ page: Some(this.state.page),
+ limit: Some(fetchLimit),
+ auth: auth(false).ok(),
+ });
WebSocketService.Instance.send(wsClient.getPersonDetails(form));
}
- get isCurrentUser() {
- return (
- UserService.Instance.myUserInfo?.local_user_view.person.id ==
- this.state.personRes.person_view.person.id
- );
+ get amCurrentUser() {
+ return UserService.Instance.myUserInfo.match({
+ some: mui =>
+ this.state.personRes.match({
+ some: res =>
+ mui.local_user_view.person.id == res.person_view.person.id,
+ none: false,
+ }),
+ none: false,
+ });
+ }
+
+ setPersonBlock() {
+ UserService.Instance.myUserInfo.match({
+ some: mui =>
+ this.state.personRes.match({
+ some: res =>
+ this.setState({
+ personBlocked: mui.person_blocks
+ .map(a => a.target.id)
+ .includes(res.person_view.person.id),
+ }),
+ none: void 0,
+ }),
+ none: void 0,
+ });
}
static getViewFromProps(view: string): PersonDetailsView {
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split("/");
- let promises: Promise<any>[] = [];
-
- // It can be /u/me, or /username/1
- let idOrName = pathSplit[2];
- let person_id: number;
- let username: string;
- if (isNaN(Number(idOrName))) {
- username = idOrName;
- } else {
- person_id = Number(idOrName);
- }
+ let username = pathSplit[2];
let view = this.getViewFromProps(pathSplit[4]);
- let sort = this.getSortTypeFromProps(pathSplit[6]);
- let page = this.getPageFromProps(Number(pathSplit[8]));
+ let sort = Some(this.getSortTypeFromProps(pathSplit[6]));
+ let page = Some(this.getPageFromProps(Number(pathSplit[8])));
- let form: GetPersonDetails = {
+ let form = new GetPersonDetails({
+ username: Some(username),
+ person_id: None,
+ community_id: None,
sort,
- saved_only: view === PersonDetailsView.Saved,
+ saved_only: Some(view === PersonDetailsView.Saved),
page,
- limit: fetchLimit,
- };
- setOptionalAuth(form, req.auth);
- this.setIdOrName(form, person_id, username);
- promises.push(req.client.getPersonDetails(form));
- return promises;
+ limit: Some(fetchLimit),
+ auth: req.auth,
+ });
+ return [req.client.getPersonDetails(form)];
}
- static setIdOrName(obj: any, id: number, name_: string) {
- if (id) {
- obj.person_id = id;
- } else {
- obj.username = name_;
- }
+ componentDidMount() {
+ this.setPersonBlock();
+ setupTippy();
}
componentWillUnmount() {
}
get documentTitle(): string {
- return `@${this.state.personRes.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`;
- }
-
- get bioTag(): string {
- return this.state.personRes.person_view.person.bio
- ? previewLines(this.state.personRes.person_view.person.bio)
- : undefined;
+ return this.state.personRes.match({
+ some: res =>
+ `@${res.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`,
+ none: "",
+ });
}
render() {
return (
- <div class="container">
+ <div className="container-lg">
{this.state.loading ? (
<h5>
<Spinner large />
</h5>
) : (
- <div class="row">
- <div class="col-12 col-md-8">
- <>
- <HtmlTags
- title={this.documentTitle}
- path={this.context.router.route.match.url}
- description={this.bioTag}
- image={this.state.personRes.person_view.person.avatar}
- />
- {this.userInfo()}
- <hr />
- </>
- {!this.state.loading && this.selects()}
- <PersonDetails
- personRes={this.state.personRes}
- admins={this.state.siteRes.admins}
- sort={this.state.sort}
- page={this.state.page}
- limit={fetchLimit}
- enableDownvotes={
- this.state.siteRes.site_view.site.enable_downvotes
- }
- enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
- view={this.state.view}
- onPageChange={this.handlePageChange}
- />
- </div>
-
- {!this.state.loading && (
- <div class="col-12 col-md-4">
- {this.moderates()}
- {this.isCurrentUser && this.follows()}
+ this.state.personRes.match({
+ some: res => (
+ <div className="row">
+ <div className="col-12 col-md-8">
+ <>
+ <HtmlTags
+ title={this.documentTitle}
+ path={this.context.router.route.match.url}
+ description={res.person_view.person.bio}
+ image={res.person_view.person.avatar}
+ />
+ {this.userInfo()}
+ <hr />
+ </>
+ {!this.state.loading && this.selects()}
+ <PersonDetails
+ personRes={res}
+ admins={this.state.siteRes.admins}
+ sort={this.state.sort}
+ page={this.state.page}
+ limit={fetchLimit}
+ enableDownvotes={enableDownvotes(this.state.siteRes)}
+ enableNsfw={enableNsfw(this.state.siteRes)}
+ view={this.state.view}
+ onPageChange={this.handlePageChange}
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ />
+ </div>
+
+ {!this.state.loading && (
+ <div className="col-12 col-md-4">
+ {this.moderates()}
+ {this.amCurrentUser && this.follows()}
+ </div>
+ )}
</div>
- )}
- </div>
+ ),
+ none: <></>,
+ })
)}
</div>
);
viewRadios() {
return (
- <div class="btn-group btn-group-toggle flex-wrap mb-2">
+ <div className="btn-group btn-group-toggle flex-wrap mb-2">
<label
className={`btn btn-outline-secondary pointer
${this.state.view == PersonDetailsView.Overview && "active"}
}
selects() {
+ let profileRss = `/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`;
+
return (
<div className="mb-2">
- <span class="mr-3">{this.viewRadios()}</span>
+ <span className="mr-3">{this.viewRadios()}</span>
<SortSelect
sort={this.state.sort}
onChange={this.handleSortChange}
hideHot
hideMostComments
/>
- <a
- href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
- rel="noopener"
- title="RSS"
- >
+ <a href={profileRss} rel={relTags} title="RSS">
<Icon icon="rss" classes="text-muted small mx-2" />
</a>
+ <link rel="alternate" type="application/atom+xml" href={profileRss} />
</div>
);
}
+ handleBlockPerson(personId: number) {
+ if (personId != 0) {
+ let blockUserForm = new BlockPerson({
+ person_id: personId,
+ block: true,
+ auth: auth().unwrap(),
+ });
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
+ }
+ handleUnblockPerson(recipientId: number) {
+ let blockUserForm = new BlockPerson({
+ person_id: recipientId,
+ block: false,
+ auth: auth().unwrap(),
+ });
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
userInfo() {
- let pv = this.state.personRes?.person_view;
-
- return (
- <div>
- <BannerIconHeader banner={pv.person.banner} icon={pv.person.avatar} />
- <div class="mb-3">
- <div class="">
- <div class="mb-0 d-flex flex-wrap">
- <div>
- {pv.person.display_name && (
- <h5 class="mb-0">{pv.person.display_name}</h5>
- )}
- <ul class="list-inline mb-2">
- <li className="list-inline-item">
- <PersonListing
- person={pv.person}
- realLink
- useApubName
- muted
- hideAvatar
- />
- </li>
- {pv.person.banned && (
- <li className="list-inline-item badge badge-danger">
- {i18n.t("banned")}
+ return this.state.personRes
+ .map(r => r.person_view)
+ .match({
+ some: pv => (
+ <div>
+ <BannerIconHeader
+ banner={pv.person.banner}
+ icon={pv.person.avatar}
+ />
+ <div className="mb-3">
+ <div className="">
+ <div className="mb-0 d-flex flex-wrap">
+ <div>
+ {pv.person.display_name.match({
+ some: displayName => (
+ <h5 className="mb-0">{displayName}</h5>
+ ),
+ none: <></>,
+ })}
+ <ul className="list-inline mb-2">
+ <li className="list-inline-item">
+ <PersonListing
+ person={pv.person}
+ realLink
+ useApubName
+ muted
+ hideAvatar
+ />
+ </li>
+ {isBanned(pv.person) && (
+ <li className="list-inline-item badge badge-danger">
+ {i18n.t("banned")}
+ </li>
+ )}
+ {pv.person.deleted && (
+ <li className="list-inline-item badge badge-danger">
+ {i18n.t("deleted")}
+ </li>
+ )}
+ {pv.person.admin && (
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("admin")}
+ </li>
+ )}
+ {pv.person.bot_account && (
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("bot_account").toLowerCase()}
+ </li>
+ )}
+ </ul>
+ </div>
+ {this.banDialog()}
+ <div className="flex-grow-1 unselectable pointer mx-2"></div>
+ {!this.amCurrentUser &&
+ UserService.Instance.myUserInfo.isSome() && (
+ <>
+ <a
+ className={`d-flex align-self-start btn btn-secondary mr-2 ${
+ !pv.person.matrix_user_id && "invisible"
+ }`}
+ rel={relTags}
+ href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
+ >
+ {i18n.t("send_secure_message")}
+ </a>
+ <Link
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ to={`/create_private_message/recipient/${pv.person.id}`}
+ >
+ {i18n.t("send_message")}
+ </Link>
+ {this.state.personBlocked ? (
+ <button
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ onClick={linkEvent(
+ pv.person.id,
+ this.handleUnblockPerson
+ )}
+ >
+ {i18n.t("unblock_user")}
+ </button>
+ ) : (
+ <button
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ onClick={linkEvent(
+ pv.person.id,
+ this.handleBlockPerson
+ )}
+ >
+ {i18n.t("block_user")}
+ </button>
+ )}
+ </>
+ )}
+
+ {canMod(
+ None,
+ Some(this.state.siteRes.admins),
+ pv.person.id
+ ) &&
+ !isAdmin(Some(this.state.siteRes.admins), pv.person.id) &&
+ !this.state.showBanDialog &&
+ (!isBanned(pv.person) ? (
+ <button
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ onClick={linkEvent(this, this.handleModBanShow)}
+ aria-label={i18n.t("ban")}
+ >
+ {capitalizeFirstLetter(i18n.t("ban"))}
+ </button>
+ ) : (
+ <button
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ onClick={linkEvent(this, this.handleModBanSubmit)}
+ aria-label={i18n.t("unban")}
+ >
+ {capitalizeFirstLetter(i18n.t("unban"))}
+ </button>
+ ))}
+ </div>
+ {pv.person.bio.match({
+ some: bio => (
+ <div className="d-flex align-items-center mb-2">
+ <div
+ className="md-div"
+ dangerouslySetInnerHTML={mdToHtml(bio)}
+ />
+ </div>
+ ),
+ none: <></>,
+ })}
+ <div>
+ <ul className="list-inline mb-2">
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("number_of_posts", {
+ count: pv.counts.post_count,
+ formattedCount: numToSI(pv.counts.post_count),
+ })}
+ </li>
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("number_of_comments", {
+ count: pv.counts.comment_count,
+ formattedCount: numToSI(pv.counts.comment_count),
+ })}
</li>
- )}
- </ul>
+ </ul>
+ </div>
+ <div className="text-muted">
+ {i18n.t("joined")}{" "}
+ <MomentTime
+ published={pv.person.published}
+ updated={None}
+ showAgo
+ ignoreUpdated
+ />
+ </div>
+ <div className="d-flex align-items-center text-muted mb-2">
+ <Icon icon="cake" />
+ <span className="ml-2">
+ {i18n.t("cake_day_title")}{" "}
+ {moment
+ .utc(pv.person.published)
+ .local()
+ .format("MMM DD, YYYY")}
+ </span>
+ </div>
</div>
- <div className="flex-grow-1 unselectable pointer mx-2"></div>
- {!this.isCurrentUser && (
- <>
- <a
- className={`d-flex align-self-start btn btn-secondary mr-2 ${
- !pv.person.matrix_user_id && "invisible"
- }`}
- rel="noopener"
- href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
+ </div>
+ </div>
+ ),
+ none: <></>,
+ });
+ }
+
+ banDialog() {
+ return this.state.personRes
+ .map(r => r.person_view)
+ .match({
+ some: pv => (
+ <>
+ {this.state.showBanDialog && (
+ <form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
+ <div className="form-group row col-12">
+ <label
+ className="col-form-label"
+ htmlFor="profile-ban-reason"
>
- {i18n.t("send_secure_message")}
- </a>
- <Link
- className={"d-flex align-self-start btn btn-secondary"}
- to={`/create_private_message/recipient/${pv.person.id}`}
+ {i18n.t("reason")}
+ </label>
+ <input
+ type="text"
+ id="profile-ban-reason"
+ className="form-control mr-2"
+ placeholder={i18n.t("reason")}
+ value={toUndefined(this.state.banReason)}
+ onInput={linkEvent(this, this.handleModBanReasonChange)}
+ />
+ <label className="col-form-label" htmlFor={`mod-ban-expires`}>
+ {i18n.t("expires")}
+ </label>
+ <input
+ type="number"
+ id={`mod-ban-expires`}
+ className="form-control mr-2"
+ placeholder={i18n.t("number_of_days")}
+ value={toUndefined(this.state.banExpireDays)}
+ onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
+ />
+ <div className="form-group">
+ <div className="form-check">
+ <input
+ className="form-check-input"
+ id="mod-ban-remove-data"
+ type="checkbox"
+ checked={this.state.removeData}
+ onChange={linkEvent(
+ this,
+ this.handleModRemoveDataChange
+ )}
+ />
+ <label
+ className="form-check-label"
+ htmlFor="mod-ban-remove-data"
+ title={i18n.t("remove_content_more")}
+ >
+ {i18n.t("remove_content")}
+ </label>
+ </div>
+ </div>
+ </div>
+ {/* TODO hold off on expires until later */}
+ {/* <div class="form-group row"> */}
+ {/* <label class="col-form-label">Expires</label> */}
+ {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
+ {/* </div> */}
+ <div className="form-group row">
+ <button
+ type="reset"
+ className="btn btn-secondary mr-2"
+ aria-label={i18n.t("cancel")}
+ onClick={linkEvent(this, this.handleModBanSubmitCancel)}
>
- {i18n.t("send_message")}
- </Link>
- </>
- )}
- </div>
- {pv.person.bio && (
- <div className="d-flex align-items-center mb-2">
- <div
- className="md-div"
- dangerouslySetInnerHTML={mdToHtml(pv.person.bio)}
- />
- </div>
+ {i18n.t("cancel")}
+ </button>
+ <button
+ type="submit"
+ className="btn btn-secondary"
+ aria-label={i18n.t("ban")}
+ >
+ {i18n.t("ban")} {pv.person.name}
+ </button>
+ </div>
+ </form>
)}
- <div>
- <ul class="list-inline mb-2">
- <li className="list-inline-item badge badge-light">
- {i18n.t("number_of_posts", { count: pv.counts.post_count })}
- </li>
- <li className="list-inline-item badge badge-light">
- {i18n.t("number_of_comments", {
- count: pv.counts.comment_count,
- })}
- </li>
- </ul>
- </div>
- <div class="text-muted">
- {i18n.t("joined")}{" "}
- <MomentTime data={pv.person} showAgo ignoreUpdated />
- </div>
- <div className="d-flex align-items-center text-muted mb-2">
- <Icon icon="cake" />
- <span className="ml-2">
- {i18n.t("cake_day_title")}{" "}
- {moment.utc(pv.person.published).local().format("MMM DD, YYYY")}
- </span>
- </div>
- </div>
- </div>
- </div>
- );
+ </>
+ ),
+ none: <></>,
+ });
}
moderates() {
- return (
- <div>
- {this.state.personRes.moderates.length > 0 && (
- <div class="card border-secondary mb-3">
- <div class="card-body">
- <h5>{i18n.t("moderates")}</h5>
- <ul class="list-unstyled mb-0">
- {this.state.personRes.moderates.map(cmv => (
- <li>
- <CommunityLink community={cmv.community} />
- </li>
- ))}
- </ul>
- </div>
- </div>
- )}
- </div>
- );
+ return this.state.personRes
+ .map(r => r.moderates)
+ .match({
+ some: moderates => {
+ if (moderates.length > 0) {
+ return (
+ <div className="card border-secondary mb-3">
+ <div className="card-body">
+ <h5>{i18n.t("moderates")}</h5>
+ <ul className="list-unstyled mb-0">
+ {moderates.map(cmv => (
+ <li key={cmv.community.id}>
+ <CommunityLink community={cmv.community} />
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ );
+ } else {
+ return <></>;
+ }
+ },
+ none: void 0,
+ });
}
follows() {
- let follows = UserService.Instance.myUserInfo.follows;
- return (
- <div>
- {follows.length > 0 && (
- <div class="card border-secondary mb-3">
- <div class="card-body">
- <h5>{i18n.t("subscribed")}</h5>
- <ul class="list-unstyled mb-0">
- {follows.map(cfv => (
- <li>
- <CommunityLink community={cfv.community} />
- </li>
- ))}
- </ul>
- </div>
- </div>
- )}
- </div>
- );
+ return UserService.Instance.myUserInfo
+ .map(m => m.follows)
+ .match({
+ some: follows => {
+ if (follows.length > 0) {
+ return (
+ <div className="card border-secondary mb-3">
+ <div className="card-body">
+ <h5>{i18n.t("subscribed")}</h5>
+ <ul className="list-unstyled mb-0">
+ {follows.map(cfv => (
+ <li key={cfv.community.id}>
+ <CommunityLink community={cfv.community} />
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ );
+ } else {
+ return <></>;
+ }
+ },
+ none: void 0,
+ });
}
updateUrl(paramUpdates: UrlParams) {
this.props.history.push(
`${typeView}/view/${viewStr}/sort/${sortStr}/page/${page}`
);
- this.state.loading = true;
- this.setState(this.state);
+ this.setState({ loading: true });
this.fetchUserData();
}
handlePageChange(page: number) {
- this.updateUrl({ page });
+ this.updateUrl({ page: page });
}
handleSortChange(val: SortType) {
});
}
+ handleModBanShow(i: Profile) {
+ i.setState({ showBanDialog: true });
+ }
+
+ handleModBanReasonChange(i: Profile, event: any) {
+ i.setState({ banReason: event.target.value });
+ }
+
+ handleModBanExpireDaysChange(i: Profile, event: any) {
+ i.setState({ banExpireDays: event.target.value });
+ }
+
+ handleModRemoveDataChange(i: Profile, event: any) {
+ i.setState({ removeData: event.target.checked });
+ }
+
+ handleModBanSubmitCancel(i: Profile, event?: any) {
+ event.preventDefault();
+ i.setState({ showBanDialog: false });
+ }
+
+ handleModBanSubmit(i: Profile, event?: any) {
+ if (event) event.preventDefault();
+
+ i.state.personRes
+ .map(r => r.person_view.person)
+ .match({
+ some: person => {
+ // If its an unban, restore all their data
+ let ban = !person.banned;
+ if (ban == false) {
+ i.setState({ removeData: false });
+ }
+ let form = new BanPerson({
+ person_id: person.id,
+ ban,
+ remove_data: Some(i.state.removeData),
+ reason: i.state.banReason,
+ expires: i.state.banExpireDays.map(futureDaysToUnixTime),
+ auth: auth().unwrap(),
+ });
+ WebSocketService.Instance.send(wsClient.banPerson(form));
+
+ i.setState({ showBanDialog: false });
+ },
+ none: void 0,
+ });
+ }
+
parseMessage(msg: any) {
let op = wsUserOp(msg);
console.log(msg);
// Since the PersonDetails contains posts/comments as well as some general user info we listen here as well
// and set the parent state if it is not set or differs
// TODO this might need to get abstracted
- let data = wsJsonToRes<GetPersonDetailsResponse>(msg).data;
- this.state.personRes = data;
- console.log(data);
- this.state.loading = false;
- this.setState(this.state);
+ let data = wsJsonToRes<GetPersonDetailsResponse>(
+ msg,
+ GetPersonDetailsResponse
+ );
+ this.setState({ personRes: Some(data), loading: false });
+ this.setPersonBlock();
restoreScrollPosition(this.context);
} else if (op == UserOperation.AddAdmin) {
- let data = wsJsonToRes<AddAdminResponse>(msg).data;
- this.state.siteRes.admins = data.admins;
- this.setState(this.state);
+ let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
+ this.setState(s => ((s.siteRes.admins = data.admins), s));
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg).data;
- createCommentLikeRes(data.comment_view, this.state.personRes.comments);
+ let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ createCommentLikeRes(
+ data.comment_view,
+ this.state.personRes.map(r => r.comments).unwrapOr([])
+ );
this.setState(this.state);
} else if (
op == UserOperation.EditComment ||
op == UserOperation.DeleteComment ||
op == UserOperation.RemoveComment
) {
- let data = wsJsonToRes<CommentResponse>(msg).data;
- editCommentRes(data.comment_view, this.state.personRes.comments);
+ let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ editCommentRes(
+ data.comment_view,
+ this.state.personRes.map(r => r.comments).unwrapOr([])
+ );
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
- let data = wsJsonToRes<CommentResponse>(msg).data;
- if (
- UserService.Instance.myUserInfo &&
- data.comment_view.creator.id ==
- UserService.Instance.myUserInfo.local_user_view.person.id
- ) {
- toast(i18n.t("reply_sent"));
- }
+ let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ UserService.Instance.myUserInfo.match({
+ some: mui => {
+ if (data.comment_view.creator.id == mui.local_user_view.person.id) {
+ toast(i18n.t("reply_sent"));
+ }
+ },
+ none: void 0,
+ });
} else if (op == UserOperation.SaveComment) {
- let data = wsJsonToRes<CommentResponse>(msg).data;
- saveCommentRes(data.comment_view, this.state.personRes.comments);
+ let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ saveCommentRes(
+ data.comment_view,
+ this.state.personRes.map(r => r.comments).unwrapOr([])
+ );
this.setState(this.state);
} else if (
op == UserOperation.EditPost ||
op == UserOperation.DeletePost ||
op == UserOperation.RemovePost ||
op == UserOperation.LockPost ||
- op == UserOperation.StickyPost ||
+ op == UserOperation.FeaturePost ||
op == UserOperation.SavePost
) {
- let data = wsJsonToRes<PostResponse>(msg).data;
- editPostFindRes(data.post_view, this.state.personRes.posts);
+ let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ editPostFindRes(
+ data.post_view,
+ this.state.personRes.map(r => r.posts).unwrapOr([])
+ );
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
- let data = wsJsonToRes<PostResponse>(msg).data;
- createPostLikeFindRes(data.post_view, this.state.personRes.posts);
+ let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ createPostLikeFindRes(
+ data.post_view,
+ this.state.personRes.map(r => r.posts).unwrapOr([])
+ );
this.setState(this.state);
} else if (op == UserOperation.BanPerson) {
- let data = wsJsonToRes<BanPersonResponse>(msg).data;
- this.state.personRes.comments
- .filter(c => c.creator.id == data.person_view.person.id)
- .forEach(c => (c.creator.banned = data.banned));
- this.state.personRes.posts
- .filter(c => c.creator.id == data.person_view.person.id)
- .forEach(c => (c.creator.banned = data.banned));
- this.setState(this.state);
+ let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
+ this.state.personRes.match({
+ some: res => {
+ res.comments
+ .filter(c => c.creator.id == data.person_view.person.id)
+ .forEach(c => (c.creator.banned = data.banned));
+ res.posts
+ .filter(c => c.creator.id == data.person_view.person.id)
+ .forEach(c => (c.creator.banned = data.banned));
+ let pv = res.person_view;
+
+ if (pv.person.id == data.person_view.person.id) {
+ pv.person.banned = data.banned;
+ }
+ this.setState(this.state);
+ },
+ none: void 0,
+ });
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg).data;
+ let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
updatePersonBlock(data);
+ this.setPersonBlock();
+ this.setState(this.state);
+ } else if (
+ op == UserOperation.PurgePerson ||
+ op == UserOperation.PurgePost ||
+ op == UserOperation.PurgeComment ||
+ op == UserOperation.PurgeCommunity
+ ) {
+ let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+ if (data.success) {
+ toast(i18n.t("purge_success"));
+ this.context.router.history.push(`/`);
+ }
}
}
}