}}
/>
<span class="mx-2">•</span>
- <Link class="mr-2" to={`/post/${node.comment.post_id}`}>
+ <Link className="mr-2" to={`/post/${node.comment.post_id}`}>
{node.comment.post_name}
</Link>
</>
{!this.myComment && (
<button class="btn btn-link btn-animate">
<Link
- class="text-muted"
+ className="text-muted"
to={`/create_private_message/recipient/${node.comment.creator_id}`}
title={i18n.t('message').toLowerCase()}
>
let node = this.props.node;
return (
<Link
- class="btn btn-link btn-animate text-muted"
+ className="btn btn-link btn-animate text-muted"
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
title={this.props.showContext ? i18n.t('show_context') : i18n.t('link')}
>
import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
import {
UserOperation,
Comment,
GetPrivateMessagesForm,
PrivateMessagesResponse,
PrivateMessageResponse,
- GetSiteResponse,
Site,
} from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
createCommentLikeRes,
commentsToFlatNodes,
setupTippy,
+ setIsoData,
+ wsSubscribe,
+ lemmyHttp,
+ setAuth,
+ isBrowser,
} from '../utils';
import { CommentNodes } from './comment-nodes';
import { PrivateMessage } from './private-message';
sort: SortType;
page: number;
site: Site;
+ loading: boolean;
}
export class Inbox extends Component<any, InboxState> {
+ private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: InboxState = {
unreadOrAll: UnreadOrAll.Unread,
messages: [],
sort: SortType.New,
page: 1,
- site: {
- id: undefined,
- name: undefined,
- creator_id: undefined,
- published: undefined,
- creator_name: undefined,
- number_of_users: undefined,
- number_of_posts: undefined,
- number_of_comments: undefined,
- number_of_communities: undefined,
- enable_downvotes: undefined,
- open_registration: undefined,
- enable_nsfw: undefined,
- },
+ site: this.isoData.site.site,
+ loading: true,
};
constructor(props: any, context: any) {
this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
- this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- msg => this.parseMessage(msg),
- err => console.error(err),
- () => console.log('complete')
- );
+ this.parseMessage = this.parseMessage.bind(this);
+ this.subscription = wsSubscribe(this.parseMessage);
- this.refetch();
- WebSocketService.Instance.getSite();
+ // Only fetch the data if coming from another route
+ if (this.isoData.path == this.context.router.route.match.url) {
+ this.state.replies = this.isoData.routeData[0].replies;
+ this.state.mentions = this.isoData.routeData[1].mentions;
+ this.state.messages = this.isoData.routeData[2].messages;
+ this.sendUnreadCount();
+ this.state.loading = false;
+ } else {
+ this.refetch();
+ }
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ if (isBrowser()) {
+ this.subscription.unsubscribe();
+ }
}
get documentTitle(): string {
- if (this.state.site.name) {
- return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${
- this.state.site.name
- }`;
- } else {
- return 'Lemmy';
- }
+ return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${
+ this.state.site.name
+ }`;
}
render() {
return (
<div class="container">
<Helmet title={this.documentTitle} />
- <div class="row">
- <div class="col-12">
- <h5 class="mb-1">
- {i18n.t('inbox')}
- <small>
- <a
- href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
- target="_blank"
- title="RSS"
- rel="noopener"
- >
- <svg class="icon ml-2 text-muted small">
- <use xlinkHref="#icon-rss">#</use>
- </svg>
- </a>
- </small>
- </h5>
- {this.state.replies.length +
- this.state.mentions.length +
- this.state.messages.length >
- 0 &&
- this.state.unreadOrAll == UnreadOrAll.Unread && (
- <ul class="list-inline mb-1 text-muted small font-weight-bold">
- <li className="list-inline-item">
- <span
- class="pointer"
- onClick={linkEvent(this, this.markAllAsRead)}
- >
- {i18n.t('mark_all_as_read')}
- </span>
- </li>
- </ul>
- )}
- {this.selects()}
- {this.state.messageType == MessageType.All && this.all()}
- {this.state.messageType == MessageType.Replies && this.replies()}
- {this.state.messageType == MessageType.Mentions && this.mentions()}
- {this.state.messageType == MessageType.Messages && this.messages()}
- {this.paginator()}
+ {this.state.loading ? (
+ <h5>
+ <svg class="icon icon-spinner spin">
+ <use xlinkHref="#icon-spinner"></use>
+ </svg>
+ </h5>
+ ) : (
+ <div class="row">
+ <div class="col-12">
+ <h5 class="mb-1">
+ {i18n.t('inbox')}
+ <small>
+ <a
+ href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
+ target="_blank"
+ title="RSS"
+ rel="noopener"
+ >
+ <svg class="icon ml-2 text-muted small">
+ <use xlinkHref="#icon-rss">#</use>
+ </svg>
+ </a>
+ </small>
+ </h5>
+ {this.state.replies.length +
+ this.state.mentions.length +
+ this.state.messages.length >
+ 0 &&
+ this.state.unreadOrAll == UnreadOrAll.Unread && (
+ <ul class="list-inline mb-1 text-muted small font-weight-bold">
+ <li className="list-inline-item">
+ <span
+ class="pointer"
+ onClick={linkEvent(this, this.markAllAsRead)}
+ >
+ {i18n.t('mark_all_as_read')}
+ </span>
+ </li>
+ </ul>
+ )}
+ {this.selects()}
+ {this.state.messageType == MessageType.All && this.all()}
+ {this.state.messageType == MessageType.Replies && this.replies()}
+ {this.state.messageType == MessageType.Mentions &&
+ this.mentions()}
+ {this.state.messageType == MessageType.Messages &&
+ this.messages()}
+ {this.paginator()}
+ </div>
</div>
- </div>
+ )}
</div>
);
}
i.refetch();
}
+ static fetchInitialData(auth: string, _path: string): Promise<any>[] {
+ let promises: Promise<any>[] = [];
+
+ // It can be /u/me, or /username/1
+ let repliesForm: GetRepliesForm = {
+ sort: SortType.New,
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ };
+ setAuth(repliesForm, auth);
+ promises.push(lemmyHttp.getReplies(repliesForm));
+
+ let userMentionsForm: GetUserMentionsForm = {
+ sort: SortType.New,
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ };
+ setAuth(userMentionsForm, auth);
+ promises.push(lemmyHttp.getUserMentions(userMentionsForm));
+
+ let privateMessagesForm: GetPrivateMessagesForm = {
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ };
+ setAuth(privateMessagesForm, auth);
+ promises.push(lemmyHttp.getPrivateMessages(privateMessagesForm));
+
+ return promises;
+ }
+
refetch() {
let repliesForm: GetRepliesForm = {
sort: this.state.sort,
} else if (res.op == UserOperation.GetReplies) {
let data = res.data as GetRepliesResponse;
this.state.replies = data.replies;
+ this.state.loading = false;
this.sendUnreadCount();
window.scrollTo(0, 0);
this.setState(this.state);
let data = res.data as CommentResponse;
createCommentLikeRes(data, this.state.replies);
this.setState(this.state);
- } else if (res.op == UserOperation.GetSite) {
- let data = res.data as GetSiteResponse;
- this.state.site = data.site;
- this.setState(this.state);
}
}
}
}
+ this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
}
AddAdminForm,
TransferSiteForm,
TransferCommunityForm,
+ Community,
} from 'lemmy-js-client';
import { BanType } from '../interfaces';
import { MomentTime } from './moment-time';
interface PostListingProps {
post: Post;
+ communities: Community[];
showCommunity?: boolean;
showBody?: boolean;
moderators?: CommunityUser[];
onCancel={this.handleEditCancel}
enableNsfw={this.props.enableNsfw}
enableDownvotes={this.props.enableDownvotes}
+ communities={this.props.communities}
/>
</div>
)}
}
} else if (post.thumbnail_url) {
return pictrsImage(post.thumbnail_url, thumbnail);
+ } else {
+ return null;
}
}
</li>
<li className="list-inline-item">
<Link
- class="btn btn-link btn-animate text-muted"
+ className="btn btn-link btn-animate text-muted"
to={`/create_post${this.crossPostParams}`}
title={i18n.t('cross_post')}
>
import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
import {
UserOperation,
- Community,
Post as PostI,
GetPostResponse,
PostResponse,
- Comment,
MarkCommentAsReadForm,
CommentResponse,
- CommunityUser,
CommunityResponse,
CommentNode as CommentNodeI,
BanFromCommunityResponse,
GetSiteResponse,
GetCommunityResponse,
WebSocketJsonResponse,
+ ListCategoriesResponse,
+ Category,
} from 'lemmy-js-client';
import { CommentSortType, CommentViewType } from '../interfaces';
import { WebSocketService, UserService } from '../services';
commentsToFlatNodes,
setupTippy,
favIconUrl,
+ setIsoData,
+ getIdFromProps,
+ getCommentIdFromProps,
+ wsSubscribe,
+ setAuth,
+ lemmyHttp,
+ isBrowser,
} from '../utils';
import { PostListing } from './post-listing';
import { Sidebar } from './sidebar';
import { i18n } from '../i18next';
interface PostState {
- post: PostI;
- comments: Comment[];
+ postRes: GetPostResponse;
+ postId: number;
+ commentId?: number;
commentSort: CommentSortType;
commentViewType: CommentViewType;
- community: Community;
- moderators: CommunityUser[];
- online: number;
scrolled?: boolean;
- scrolled_comment_id?: number;
loading: boolean;
crossPosts: PostI[];
siteRes: GetSiteResponse;
+ categories: Category[];
}
export class Post extends Component<any, PostState> {
private subscription: Subscription;
+ private isoData = setIsoData(this.context);
private emptyState: PostState = {
- post: null,
- comments: [],
+ postRes: null,
+ postId: getIdFromProps(this.props),
+ commentId: getCommentIdFromProps(this.props),
commentSort: CommentSortType.Hot,
commentViewType: CommentViewType.Tree,
- community: null,
- moderators: [],
- online: null,
scrolled: false,
loading: true,
crossPosts: [],
- siteRes: {
- admins: [],
- banned: [],
- site: {
- id: undefined,
- name: undefined,
- creator_id: undefined,
- published: undefined,
- creator_name: undefined,
- number_of_users: undefined,
- number_of_posts: undefined,
- number_of_comments: undefined,
- number_of_communities: undefined,
- enable_downvotes: undefined,
- open_registration: undefined,
- enable_nsfw: undefined,
- icon: undefined,
- banner: undefined,
- },
- online: null,
- version: null,
- federated_instances: undefined,
- },
+ siteRes: this.isoData.site,
+ categories: [],
};
constructor(props: any, context: any) {
this.state = this.emptyState;
- let postId = Number(this.props.match.params.id);
- if (this.props.match.params.comment_id) {
- this.state.scrolled_comment_id = this.props.match.params.comment_id;
- }
+ this.parseMessage = this.parseMessage.bind(this);
+ this.subscription = wsSubscribe(this.parseMessage);
- this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- msg => this.parseMessage(msg),
- err => console.error(err),
- () => console.log('complete')
- );
+ // Only fetch the data if coming from another route
+ if (this.isoData.path == this.context.router.route.match.url) {
+ this.state.postRes = this.isoData.routeData[0];
+ this.state.categories = this.isoData.routeData[1].categories;
+ this.state.loading = false;
+ if (isBrowser() && this.state.commentId) {
+ this.scrollCommentIntoView();
+ }
+ } else {
+ this.fetchPost();
+ WebSocketService.Instance.listCategories();
+ }
+ }
+
+ fetchPost() {
let form: GetPostForm = {
- id: postId,
+ id: this.state.postId,
};
WebSocketService.Instance.getPost(form);
- WebSocketService.Instance.getSite();
+ }
+
+ static fetchInitialData(auth: string, path: string): Promise<any>[] {
+ let pathSplit = path.split('/');
+ let promises: Promise<any>[] = [];
+
+ let id = Number(pathSplit[2]);
+
+ let postForm: GetPostForm = {
+ id,
+ };
+ setAuth(postForm, auth);
+
+ promises.push(lemmyHttp.getPost(postForm));
+ promises.push(lemmyHttp.listCategories());
+
+ return promises;
}
componentWillUnmount() {
componentDidUpdate(_lastProps: any, lastState: PostState, _snapshot: any) {
if (
- this.state.scrolled_comment_id &&
+ this.state.commentId &&
!this.state.scrolled &&
- lastState.comments.length > 0
+ lastState.postRes &&
+ lastState.postRes.comments.length > 0
) {
- var elmnt = document.getElementById(
- `comment-${this.state.scrolled_comment_id}`
- );
- elmnt.scrollIntoView();
- elmnt.classList.add('mark');
- this.state.scrolled = true;
- this.markScrolledAsRead(this.state.scrolled_comment_id);
+ this.scrollCommentIntoView();
}
// Necessary if you are on a post and you click another post (same route)
}
}
+ scrollCommentIntoView() {
+ var elmnt = document.getElementById(`comment-${this.state.commentId}`);
+ elmnt.scrollIntoView();
+ elmnt.classList.add('mark');
+ this.state.scrolled = true;
+ this.markScrolledAsRead(this.state.commentId);
+ }
+
markScrolledAsRead(commentId: number) {
- let found = this.state.comments.find(c => c.id == commentId);
- let parent = this.state.comments.find(c => found.parent_id == c.id);
+ let found = this.state.postRes.comments.find(c => c.id == commentId);
+ let parent = this.state.postRes.comments.find(c => found.parent_id == c.id);
let parent_user_id = parent
? parent.creator_id
- : this.state.post.creator_id;
+ : this.state.postRes.post.creator_id;
if (
UserService.Instance.user &&
}
get documentTitle(): string {
- if (this.state.post) {
- return `${this.state.post.name} - ${this.state.siteRes.site.name}`;
+ if (this.state.postRes) {
+ return `${this.state.postRes.post.name} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
<div class="row">
<div class="col-12 col-md-8 mb-3">
<PostListing
- post={this.state.post}
+ communities={[this.state.postRes.community]}
+ post={this.state.postRes.post}
showBody
showCommunity
- moderators={this.state.moderators}
+ moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
enableDownvotes={this.state.siteRes.site.enable_downvotes}
enableNsfw={this.state.siteRes.site.enable_nsfw}
/>
<div className="mb-2" />
<CommentForm
- postId={this.state.post.id}
- disabled={this.state.post.locked}
+ postId={this.state.postId}
+ disabled={this.state.postRes.post.locked}
/>
- {this.state.comments.length > 0 && this.sortRadios()}
+ {this.state.postRes.comments.length > 0 && this.sortRadios()}
{this.state.commentViewType == CommentViewType.Tree &&
this.commentsTree()}
{this.state.commentViewType == CommentViewType.Chat &&
return (
<div>
<CommentNodes
- nodes={commentsToFlatNodes(this.state.comments)}
+ nodes={commentsToFlatNodes(this.state.postRes.comments)}
noIndent
- locked={this.state.post.locked}
- moderators={this.state.moderators}
+ locked={this.state.postRes.post.locked}
+ moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
- postCreatorId={this.state.post.creator_id}
+ postCreatorId={this.state.postRes.post.creator_id}
showContext
enableDownvotes={this.state.siteRes.site.enable_downvotes}
sort={this.state.commentSort}
return (
<div class="mb-3">
<Sidebar
- community={this.state.community}
- moderators={this.state.moderators}
+ community={this.state.postRes.community}
+ moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
- online={this.state.online}
+ online={this.state.postRes.online}
enableNsfw={this.state.siteRes.site.enable_nsfw}
showIcon
+ categories={this.state.categories}
/>
</div>
);
buildCommentsTree(): CommentNodeI[] {
let map = new Map<number, CommentNodeI>();
- for (let comment of this.state.comments) {
+ for (let comment of this.state.postRes.comments) {
let node: CommentNodeI = {
comment: comment,
children: [],
map.set(comment.id, { ...node });
}
let tree: CommentNodeI[] = [];
- for (let comment of this.state.comments) {
+ for (let comment of this.state.postRes.comments) {
let child = map.get(comment.id);
if (comment.parent_id) {
let parent_ = map.get(comment.parent_id);
<div>
<CommentNodes
nodes={nodes}
- locked={this.state.post.locked}
- moderators={this.state.moderators}
+ locked={this.state.postRes.post.locked}
+ moderators={this.state.postRes.moderators}
admins={this.state.siteRes.admins}
- postCreatorId={this.state.post.creator_id}
+ postCreatorId={this.state.postRes.post.creator_id}
sort={this.state.commentSort}
enableDownvotes={this.state.siteRes.site.enable_downvotes}
/>
});
} else if (res.op == UserOperation.GetPost) {
let data = res.data as GetPostResponse;
- this.state.post = data.post;
- this.state.comments = data.comments;
- this.state.community = data.community;
- this.state.moderators = data.moderators;
- this.state.online = data.online;
+ this.state.postRes = data;
this.state.loading = false;
// Get cross-posts
- if (this.state.post.url) {
+ if (this.state.postRes.post.url) {
let form: SearchForm = {
- q: this.state.post.url,
+ q: this.state.postRes.post.url,
type_: SearchType.Url,
sort: SortType.TopAll,
page: 1,
// Necessary since it might be a user reply
if (data.recipient_ids.length == 0) {
- this.state.comments.unshift(data.comment);
+ this.state.postRes.comments.unshift(data.comment);
this.setState(this.state);
}
} else if (
res.op == UserOperation.RemoveComment
) {
let data = res.data as CommentResponse;
- editCommentRes(data, this.state.comments);
+ editCommentRes(data, this.state.postRes.comments);
this.setState(this.state);
} else if (res.op == UserOperation.SaveComment) {
let data = res.data as CommentResponse;
- saveCommentRes(data, this.state.comments);
+ saveCommentRes(data, this.state.postRes.comments);
this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.CreateCommentLike) {
let data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.comments);
+ createCommentLikeRes(data, this.state.postRes.comments);
this.setState(this.state);
} else if (res.op == UserOperation.CreatePostLike) {
let data = res.data as PostResponse;
- createPostLikeRes(data, this.state.post);
+ createPostLikeRes(data, this.state.postRes.post);
this.setState(this.state);
} else if (
res.op == UserOperation.EditPost ||
res.op == UserOperation.StickyPost
) {
let data = res.data as PostResponse;
- this.state.post = data.post;
+ this.state.postRes.post = data.post;
this.setState(this.state);
setupTippy();
} else if (res.op == UserOperation.SavePost) {
let data = res.data as PostResponse;
- this.state.post = data.post;
+ this.state.postRes.post = data.post;
this.setState(this.state);
setupTippy();
} else if (
res.op == UserOperation.RemoveCommunity
) {
let data = res.data as CommunityResponse;
- this.state.community = data.community;
- this.state.post.community_id = data.community.id;
- this.state.post.community_name = data.community.name;
+ this.state.postRes.community = data.community;
+ this.state.postRes.post.community_id = data.community.id;
+ this.state.postRes.post.community_name = data.community.name;
this.setState(this.state);
} else if (res.op == UserOperation.FollowCommunity) {
let data = res.data as CommunityResponse;
- this.state.community.subscribed = data.community.subscribed;
- this.state.community.number_of_subscribers =
+ this.state.postRes.community.subscribed = data.community.subscribed;
+ this.state.postRes.community.number_of_subscribers =
data.community.number_of_subscribers;
this.setState(this.state);
} else if (res.op == UserOperation.BanFromCommunity) {
let data = res.data as BanFromCommunityResponse;
- this.state.comments
+ this.state.postRes.comments
.filter(c => c.creator_id == data.user.id)
.forEach(c => (c.banned_from_community = data.banned));
- if (this.state.post.creator_id == data.user.id) {
- this.state.post.banned_from_community = data.banned;
+ if (this.state.postRes.post.creator_id == data.user.id) {
+ this.state.postRes.post.banned_from_community = data.banned;
}
this.setState(this.state);
} else if (res.op == UserOperation.AddModToCommunity) {
let data = res.data as AddModToCommunityResponse;
- this.state.moderators = data.moderators;
+ this.state.postRes.moderators = data.moderators;
this.setState(this.state);
} else if (res.op == UserOperation.BanUser) {
let data = res.data as BanUserResponse;
- this.state.comments
+ this.state.postRes.comments
.filter(c => c.creator_id == data.user.id)
.forEach(c => (c.banned = data.banned));
- if (this.state.post.creator_id == data.user.id) {
- this.state.post.banned = data.banned;
+ if (this.state.postRes.post.creator_id == data.user.id) {
+ this.state.postRes.post.banned = data.banned;
}
this.setState(this.state);
} else if (res.op == UserOperation.AddAdmin) {
p => p.id != Number(this.props.match.params.id)
);
if (this.state.crossPosts.length) {
- this.state.post.duplicates = this.state.crossPosts;
+ this.state.postRes.post.duplicates = this.state.crossPosts;
}
this.setState(this.state);
- } else if (
- res.op == UserOperation.TransferSite ||
- res.op == UserOperation.GetSite
- ) {
+ } else if (res.op == UserOperation.TransferSite) {
let data = res.data as GetSiteResponse;
this.state.siteRes = data;
this.setState(this.state);
} else if (res.op == UserOperation.TransferCommunity) {
let data = res.data as GetCommunityResponse;
- this.state.community = data.community;
- this.state.moderators = data.moderators;
+ this.state.postRes.community = data.community;
+ this.state.postRes.moderators = data.moderators;
+ this.setState(this.state);
+ } else if (res.op == UserOperation.ListCategories) {
+ let data = res.data as ListCategoriesResponse;
+ this.state.categories = data.categories;
this.setState(this.state);
}
}
import { Component, linkEvent } from 'inferno';
-import { WebSocketService, UserService } from '../services';
-import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
import { i18n } from '../i18next';
-import {
- UserOperation,
- Post,
- Comment,
- CommunityUser,
- SortType,
- UserDetailsResponse,
- UserView,
- WebSocketJsonResponse,
- CommentResponse,
- BanUserResponse,
- PostResponse,
-} from 'lemmy-js-client';
+import { Post, Comment, SortType, UserDetailsResponse } from 'lemmy-js-client';
import { UserDetailsView } from '../interfaces';
-import {
- wsJsonToRes,
- toast,
- commentsToFlatNodes,
- setupTippy,
- editCommentRes,
- saveCommentRes,
- createCommentLikeRes,
- createPostLikeFindRes,
-} from '../utils';
+import { commentsToFlatNodes, setupTippy } from '../utils';
import { PostListing } from './post-listing';
import { CommentNodes } from './comment-nodes';
interface UserDetailsProps {
- username?: string;
- user_id?: number;
+ userRes: UserDetailsResponse;
page: number;
limit: number;
sort: SortType;
enableNsfw: boolean;
view: UserDetailsView;
onPageChange(page: number): number | any;
- admins: UserView[];
}
-interface UserDetailsState {
- follows: CommunityUser[];
- moderates: CommunityUser[];
- comments: Comment[];
- posts: Post[];
- saved?: Post[];
-}
+interface UserDetailsState {}
export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
- private subscription: Subscription;
constructor(props: any, context: any) {
super(props, context);
-
- this.state = {
- follows: [],
- moderates: [],
- comments: [],
- posts: [],
- saved: [],
- };
-
- this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- msg => this.parseMessage(msg),
- err => console.error(err),
- () => console.log('complete')
- );
- }
-
- componentWillUnmount() {
- this.subscription.unsubscribe();
}
+ // TODO needed here?
componentDidMount() {
- this.fetchUserData();
setupTippy();
}
- componentDidUpdate(lastProps: UserDetailsProps) {
- for (const key of Object.keys(lastProps)) {
- if (lastProps[key] !== this.props[key]) {
- this.fetchUserData();
- break;
- }
- }
- }
-
- fetchUserData() {
- WebSocketService.Instance.getUserDetails({
- user_id: this.props.user_id,
- username: this.props.username,
- sort: this.props.sort,
- saved_only: this.props.view === UserDetailsView.Saved,
- page: this.props.page,
- limit: this.props.limit,
- });
- }
+ // TODO wut?
+ // componentDidUpdate(lastProps: UserDetailsProps) {
+ // for (const key of Object.keys(lastProps)) {
+ // if (lastProps[key] !== this.props[key]) {
+ // this.fetchUserData();
+ // break;
+ // }
+ // }
+ // }
render() {
return (
viewSelector(view: UserDetailsView) {
if (view === UserDetailsView.Overview || view === UserDetailsView.Saved) {
return this.overview();
- }
- if (view === UserDetailsView.Comments) {
+ } else if (view === UserDetailsView.Comments) {
return this.comments();
- }
- if (view === UserDetailsView.Posts) {
+ } else if (view === UserDetailsView.Posts) {
return this.posts();
+ } else {
+ return null;
}
}
overview() {
- const comments = this.state.comments.map((c: Comment) => {
+ const comments = this.props.userRes.comments.map((c: Comment) => {
return { type: 'comments', data: c };
});
- const posts = this.state.posts.map((p: Post) => {
+ const posts = this.props.userRes.posts.map((p: Post) => {
return { type: 'posts', data: p };
});
<div>
{i.type === 'posts' ? (
<PostListing
+ communities={[]}
key={(i.data as Post).id}
post={i.data as Post}
- admins={this.props.admins}
+ admins={this.props.userRes.admins}
showCommunity
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
<CommentNodes
key={(i.data as Comment).id}
nodes={[{ comment: i.data as Comment }]}
- admins={this.props.admins}
+ admins={this.props.userRes.admins}
noBorder
noIndent
showCommunity
return (
<div>
<CommentNodes
- nodes={commentsToFlatNodes(this.state.comments)}
- admins={this.props.admins}
+ nodes={commentsToFlatNodes(this.props.userRes.comments)}
+ admins={this.props.userRes.admins}
noIndent
showCommunity
showContext
posts() {
return (
<div>
- {this.state.posts.map(post => (
+ {this.props.userRes.posts.map(post => (
<>
<PostListing
+ communities={[]}
post={post}
- admins={this.props.admins}
+ admins={this.props.userRes.admins}
showCommunity
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
{i18n.t('prev')}
</button>
)}
- {this.state.comments.length + this.state.posts.length > 0 && (
+ {this.props.userRes.comments.length + this.props.userRes.posts.length >
+ 0 && (
<button
class="btn btn-secondary"
onClick={linkEvent(this, this.nextPage)}
prevPage(i: UserDetails) {
i.props.onPageChange(i.props.page - 1);
}
-
- parseMessage(msg: WebSocketJsonResponse) {
- console.log(msg);
- const res = wsJsonToRes(msg);
-
- if (msg.error) {
- toast(i18n.t(msg.error), 'danger');
- if (msg.error == 'couldnt_find_that_username_or_email') {
- this.context.router.history.push('/');
- }
- return;
- } else if (msg.reconnect) {
- this.fetchUserData();
- } else if (res.op == UserOperation.GetUserDetails) {
- const data = res.data as UserDetailsResponse;
- this.setState({
- comments: data.comments,
- follows: data.follows,
- moderates: data.moderates,
- posts: data.posts,
- });
- } else if (res.op == UserOperation.CreateCommentLike) {
- const data = res.data as CommentResponse;
- createCommentLikeRes(data, this.state.comments);
- this.setState({
- comments: this.state.comments,
- });
- } else if (
- res.op == UserOperation.EditComment ||
- res.op == UserOperation.DeleteComment ||
- res.op == UserOperation.RemoveComment
- ) {
- const data = res.data as CommentResponse;
- editCommentRes(data, this.state.comments);
- this.setState({
- comments: this.state.comments,
- });
- } else if (res.op == UserOperation.CreateComment) {
- const data = res.data as CommentResponse;
- if (
- UserService.Instance.user &&
- data.comment.creator_id == UserService.Instance.user.id
- ) {
- toast(i18n.t('reply_sent'));
- }
- } else if (res.op == UserOperation.SaveComment) {
- const data = res.data as CommentResponse;
- saveCommentRes(data, this.state.comments);
- this.setState({
- comments: this.state.comments,
- });
- } else if (res.op == UserOperation.CreatePostLike) {
- const data = res.data as PostResponse;
- createPostLikeFindRes(data, this.state.posts);
- this.setState({
- posts: this.state.posts,
- });
- } else if (res.op == UserOperation.BanUser) {
- const data = res.data as BanUserResponse;
- this.state.comments
- .filter(c => c.creator_id == data.user.id)
- .forEach(c => (c.banned = data.banned));
- this.state.posts
- .filter(c => c.creator_id == data.user.id)
- .forEach(c => (c.banned = data.banned));
- this.setState({
- posts: this.state.posts,
- comments: this.state.comments,
- });
- }
- }
}
import { Helmet } from 'inferno-helmet';
import { Link } from 'inferno-router';
import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
import {
UserOperation,
- CommunityUser,
SortType,
ListingType,
- UserView,
UserSettingsForm,
LoginResponse,
DeleteAccountForm,
GetSiteResponse,
UserDetailsResponse,
AddAdminResponse,
+ GetUserDetailsForm,
+ CommentResponse,
+ PostResponse,
+ BanUserResponse,
} from 'lemmy-js-client';
import { UserDetailsView } from '../interfaces';
import { WebSocketService, UserService } from '../services';
mdToHtml,
elementUrl,
favIconUrl,
+ setIsoData,
+ getIdFromProps,
+ getUsernameFromProps,
+ wsSubscribe,
+ createCommentLikeRes,
+ editCommentRes,
+ saveCommentRes,
+ createPostLikeFindRes,
+ setAuth,
+ lemmyHttp,
} from '../utils';
import { UserListing } from './user-listing';
import { SortSelect } from './sort-select';
import { BannerIconHeader } from './banner-icon-header';
interface UserState {
- user: UserView;
- user_id: number;
- username: string;
- follows: CommunityUser[];
- moderates: CommunityUser[];
+ userRes: UserDetailsResponse;
+ userId: number;
+ userName: string;
view: UserDetailsView;
sort: SortType;
page: number;
}
export class User extends Component<any, UserState> {
+ private isoData = setIsoData(this.context);
private subscription: Subscription;
private emptyState: UserState = {
- user: {
- id: null,
- name: null,
- published: null,
- number_of_posts: null,
- post_score: null,
- number_of_comments: null,
- comment_score: null,
- banned: null,
- avatar: null,
- actor_id: null,
- local: null,
- },
- user_id: null,
- username: null,
- follows: [],
- moderates: [],
+ userRes: undefined,
+ userId: getIdFromProps(this.props),
+ userName: getUsernameFromProps(this.props),
loading: true,
view: User.getViewFromProps(this.props.match.view),
sort: User.getSortTypeFromProps(this.props.match.sort),
deleteAccountForm: {
password: null,
},
- siteRes: {
- admins: [],
- banned: [],
- online: undefined,
- site: {
- id: undefined,
- name: undefined,
- creator_id: undefined,
- published: undefined,
- creator_name: undefined,
- number_of_users: undefined,
- number_of_posts: undefined,
- number_of_comments: undefined,
- number_of_communities: undefined,
- enable_downvotes: undefined,
- open_registration: undefined,
- enable_nsfw: undefined,
- icon: undefined,
- banner: undefined,
- creator_preferred_username: undefined,
- },
- version: undefined,
- my_user: undefined,
- federated_instances: undefined,
- },
+ siteRes: this.isoData.site,
};
constructor(props: any, context: any) {
this.handleBannerUpload = this.handleBannerUpload.bind(this);
this.handleBannerRemove = this.handleBannerRemove.bind(this);
- this.state.user_id = Number(this.props.match.params.id) || null;
- this.state.username = this.props.match.params.username;
+ this.parseMessage = this.parseMessage.bind(this);
+ this.subscription = wsSubscribe(this.parseMessage);
- this.subscription = WebSocketService.Instance.subject
- .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
- .subscribe(
- msg => this.parseMessage(msg),
- err => console.error(err),
- () => console.log('complete')
- );
+ // Only fetch the data if coming from another route
+ if (this.isoData.path == this.context.router.route.match.url) {
+ this.state.userRes = this.isoData.routeData[0];
+ this.setUserInfo();
+ this.state.loading = false;
+ } else {
+ this.fetchUserData();
+ }
- WebSocketService.Instance.getSite();
setupTippy();
}
+ fetchUserData() {
+ let form: GetUserDetailsForm = {
+ user_id: this.state.userId,
+ username: this.state.userName,
+ sort: this.state.sort,
+ saved_only: this.state.view === UserDetailsView.Saved,
+ page: this.state.page,
+ limit: fetchLimit,
+ };
+ WebSocketService.Instance.getUserDetails(form);
+ }
+
get isCurrentUser() {
return (
UserService.Instance.user &&
- UserService.Instance.user.id == this.state.user.id
+ UserService.Instance.user.id == this.state.userRes.user.id
);
}
return page ? Number(page) : 1;
}
+ static fetchInitialData(auth: string, path: string): Promise<any>[] {
+ let pathSplit = path.split('/');
+ let promises: Promise<any>[] = [];
+
+ // It can be /u/me, or /username/1
+ let idOrName = pathSplit[2];
+ let user_id: number;
+ let username: string;
+ if (isNaN(Number(idOrName))) {
+ username = idOrName;
+ } else {
+ user_id = Number(idOrName);
+ }
+
+ let view = this.getViewFromProps(pathSplit[4]);
+ let sort = this.getSortTypeFromProps(pathSplit[6]);
+ let page = this.getPageFromProps(Number(pathSplit[8]));
+
+ let form: GetUserDetailsForm = {
+ sort,
+ saved_only: view === UserDetailsView.Saved,
+ page,
+ limit: fetchLimit,
+ };
+ this.setIdOrName(form, user_id, username);
+ setAuth(form, auth);
+ promises.push(lemmyHttp.getUserDetails(form));
+ return promises;
+ }
+
+ static setIdOrName(obj: any, id: number, name_: string) {
+ if (id) {
+ obj.user_id = id;
+ } else {
+ obj.username = name_;
+ }
+ }
+
componentWillUnmount() {
this.subscription.unsubscribe();
}
get documentTitle(): string {
if (this.state.siteRes.site.name) {
- return `@${this.state.username} - ${this.state.siteRes.site.name}`;
+ return `@${this.state.userName} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
href={this.favIcon}
/>
</Helmet>
- <div class="row">
- <div class="col-12 col-md-8">
- {this.state.loading ? (
- <h5>
- <svg class="icon icon-spinner spin">
- <use xlinkHref="#icon-spinner"></use>
- </svg>
- </h5>
- ) : (
+ {this.state.loading ? (
+ <h5>
+ <svg class="icon icon-spinner spin">
+ <use xlinkHref="#icon-spinner"></use>
+ </svg>
+ </h5>
+ ) : (
+ <div class="row">
+ <div class="col-12 col-md-8">
<>
{this.userInfo()}
<hr />
</>
+ {!this.state.loading && this.selects()}
+ <UserDetails
+ userRes={this.state.userRes}
+ sort={this.state.sort}
+ page={this.state.page}
+ limit={fetchLimit}
+ enableDownvotes={this.state.siteRes.site.enable_downvotes}
+ enableNsfw={this.state.siteRes.site.enable_nsfw}
+ view={this.state.view}
+ onPageChange={this.handlePageChange}
+ />
+ </div>
+
+ {!this.state.loading && (
+ <div class="col-12 col-md-4">
+ {this.isCurrentUser && this.userSettings()}
+ {this.moderates()}
+ {this.follows()}
+ </div>
)}
- {!this.state.loading && this.selects()}
- <UserDetails
- user_id={this.state.user_id}
- username={this.state.username}
- sort={this.state.sort}
- page={this.state.page}
- limit={fetchLimit}
- enableDownvotes={this.state.siteRes.site.enable_downvotes}
- enableNsfw={this.state.siteRes.site.enable_nsfw}
- admins={this.state.siteRes.admins}
- view={this.state.view}
- onPageChange={this.handlePageChange}
- />
</div>
-
- {!this.state.loading && (
- <div class="col-12 col-md-4">
- {this.isCurrentUser && this.userSettings()}
- {this.moderates()}
- {this.follows()}
- </div>
- )}
- </div>
+ )}
</div>
);
}
hideHot
/>
<a
- href={`/feeds/u/${this.state.username}.xml?sort=${this.state.sort}`}
+ href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
target="_blank"
rel="noopener"
title="RSS"
}
userInfo() {
- let user = this.state.user;
+ let user = this.state.userRes.user;
return (
<div>
- <BannerIconHeader
- banner={this.state.user.banner}
- icon={this.state.user.avatar}
- />
+ <BannerIconHeader banner={user.banner} icon={user.avatar} />
<div class="mb-3">
<div class="">
<div class="mb-0 d-flex flex-wrap">
<>
<a
className={`d-flex align-self-start btn btn-secondary ml-2 ${
- !this.state.user.matrix_user_id && 'invisible'
+ !user.matrix_user_id && 'invisible'
}`}
target="_blank"
rel="noopener"
- href={`https://matrix.to/#/${this.state.user.matrix_user_id}`}
+ href={`https://matrix.to/#/${user.matrix_user_id}`}
>
{i18n.t('send_secure_message')}
</a>
<Link
class="d-flex align-self-start btn btn-secondary ml-2"
- to={`/create_private_message/recipient/${this.state.user.id}`}
+ to={`/create_private_message/recipient/${user.id}`}
>
{i18n.t('send_message')}
</Link>
moderates() {
return (
<div>
- {this.state.moderates.length > 0 && (
+ {this.state.userRes.moderates.length > 0 && (
<div class="card bg-transparent border-secondary mb-3">
<div class="card-body">
<h5>{i18n.t('moderates')}</h5>
<ul class="list-unstyled mb-0">
- {this.state.moderates.map(community => (
+ {this.state.userRes.moderates.map(community => (
<li>
<Link to={`/c/${community.community_name}`}>
{community.community_name}
follows() {
return (
<div>
- {this.state.follows.length > 0 && (
+ {this.state.userRes.follows.length > 0 && (
<div class="card bg-transparent border-secondary mb-3">
<div class="card-body">
<h5>{i18n.t('subscribed')}</h5>
<ul class="list-unstyled mb-0">
- {this.state.follows.map(community => (
+ {this.state.userRes.follows.map(community => (
<li>
<Link to={`/c/${community.community_name}`}>
{community.community_name}
const viewStr = paramUpdates.view || UserDetailsView[this.state.view];
const sortStr = paramUpdates.sort || this.state.sort;
this.props.history.push(
- `/u/${this.state.username}/view/${viewStr}/sort/${sortStr}/page/${page}`
+ `/u/${this.state.userName}/view/${viewStr}/sort/${sortStr}/page/${page}`
);
}
i.state.userSettingsForm.matrix_user_id = event.target.value;
if (
i.state.userSettingsForm.matrix_user_id == '' &&
- !i.state.user.matrix_user_id
+ !i.state.userRes.user.matrix_user_id
) {
i.state.userSettingsForm.matrix_user_id = undefined;
}
WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
}
+ setUserInfo() {
+ if (this.isCurrentUser) {
+ this.state.userSettingsForm.show_nsfw =
+ UserService.Instance.user.show_nsfw;
+ this.state.userSettingsForm.theme = UserService.Instance.user.theme
+ ? UserService.Instance.user.theme
+ : 'darkly';
+ this.state.userSettingsForm.default_sort_type =
+ UserService.Instance.user.default_sort_type;
+ this.state.userSettingsForm.default_listing_type =
+ UserService.Instance.user.default_listing_type;
+ this.state.userSettingsForm.lang = UserService.Instance.user.lang;
+ this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
+ this.state.userSettingsForm.banner = UserService.Instance.user.banner;
+ this.state.userSettingsForm.preferred_username =
+ UserService.Instance.user.preferred_username;
+ this.state.userSettingsForm.show_avatars =
+ UserService.Instance.user.show_avatars;
+ this.state.userSettingsForm.email = UserService.Instance.user.email;
+ this.state.userSettingsForm.bio = UserService.Instance.user.bio;
+ this.state.userSettingsForm.send_notifications_to_email =
+ UserService.Instance.user.send_notifications_to_email;
+ this.state.userSettingsForm.matrix_user_id =
+ UserService.Instance.user.matrix_user_id;
+ }
+ }
+
parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
const res = wsJsonToRes(msg);
userSettingsLoading: false,
});
return;
+ } else if (msg.reconnect) {
+ this.fetchUserData();
} else if (res.op == UserOperation.GetUserDetails) {
// Since the UserDetails 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
const data = res.data as UserDetailsResponse;
-
- if (this.state.user.id !== data.user.id) {
- this.state.user = data.user;
- this.state.follows = data.follows;
- this.state.moderates = data.moderates;
-
- if (this.isCurrentUser) {
- this.state.userSettingsForm.show_nsfw =
- UserService.Instance.user.show_nsfw;
- this.state.userSettingsForm.theme = UserService.Instance.user.theme
- ? UserService.Instance.user.theme
- : 'darkly';
- this.state.userSettingsForm.default_sort_type =
- UserService.Instance.user.default_sort_type;
- this.state.userSettingsForm.default_listing_type =
- UserService.Instance.user.default_listing_type;
- this.state.userSettingsForm.lang = UserService.Instance.user.lang;
- this.state.userSettingsForm.avatar = UserService.Instance.user.avatar;
- this.state.userSettingsForm.banner = UserService.Instance.user.banner;
- this.state.userSettingsForm.preferred_username =
- UserService.Instance.user.preferred_username;
- this.state.userSettingsForm.show_avatars =
- UserService.Instance.user.show_avatars;
- this.state.userSettingsForm.email = UserService.Instance.user.email;
- this.state.userSettingsForm.bio = UserService.Instance.user.bio;
- this.state.userSettingsForm.send_notifications_to_email =
- UserService.Instance.user.send_notifications_to_email;
- this.state.userSettingsForm.matrix_user_id =
- UserService.Instance.user.matrix_user_id;
- }
- this.state.loading = false;
- this.setState(this.state);
- }
+ this.state.userRes = data;
+ this.setUserInfo();
+ this.state.loading = false;
+ this.setState(this.state);
} else if (res.op == UserOperation.SaveUserSettings) {
const data = res.data as LoginResponse;
UserService.Instance.login(data);
- this.state.user.bio = this.state.userSettingsForm.bio;
- this.state.user.preferred_username = this.state.userSettingsForm.preferred_username;
- this.state.user.banner = this.state.userSettingsForm.banner;
- this.state.user.avatar = this.state.userSettingsForm.avatar;
+ this.state.userRes.user.bio = this.state.userSettingsForm.bio;
+ this.state.userRes.user.preferred_username = this.state.userSettingsForm.preferred_username;
+ this.state.userRes.user.banner = this.state.userSettingsForm.banner;
+ this.state.userRes.user.avatar = this.state.userSettingsForm.avatar;
this.state.userSettingsLoading = false;
this.setState(this.state);
deleteAccountShowConfirm: false,
});
this.context.router.history.push('/');
- } else if (res.op == UserOperation.GetSite) {
- const data = res.data as GetSiteResponse;
- this.state.siteRes = data;
- this.setState(this.state);
} else if (res.op == UserOperation.AddAdmin) {
const data = res.data as AddAdminResponse;
this.state.siteRes.admins = data.admins;
this.setState(this.state);
+ } else if (res.op == UserOperation.CreateCommentLike) {
+ const data = res.data as CommentResponse;
+ createCommentLikeRes(data, this.state.userRes.comments);
+ this.setState(this.state);
+ } else if (
+ res.op == UserOperation.EditComment ||
+ res.op == UserOperation.DeleteComment ||
+ res.op == UserOperation.RemoveComment
+ ) {
+ const data = res.data as CommentResponse;
+ editCommentRes(data, this.state.userRes.comments);
+ this.setState(this.state);
+ } else if (res.op == UserOperation.CreateComment) {
+ const data = res.data as CommentResponse;
+ if (
+ UserService.Instance.user &&
+ data.comment.creator_id == UserService.Instance.user.id
+ ) {
+ toast(i18n.t('reply_sent'));
+ }
+ } else if (res.op == UserOperation.SaveComment) {
+ const data = res.data as CommentResponse;
+ saveCommentRes(data, this.state.userRes.comments);
+ this.setState(this.state);
+ } else if (res.op == UserOperation.CreatePostLike) {
+ const data = res.data as PostResponse;
+ createPostLikeFindRes(data, this.state.userRes.posts);
+ this.setState(this.state);
+ } else if (res.op == UserOperation.BanUser) {
+ const data = res.data as BanUserResponse;
+ this.state.userRes.comments
+ .filter(c => c.creator_id == data.user.id)
+ .forEach(c => (c.banned = data.banned));
+ this.state.userRes.posts
+ .filter(c => c.creator_id == data.user.id)
+ .forEach(c => (c.banned = data.banned));
+ this.setState(this.state);
}
}
}
{
path: `/post/:id/comment/:comment_id`,
component: Post,
+ fetchInitialData: (auth, path) => Post.fetchInitialData(auth, path),
+ },
+ {
+ path: `/post/:id`,
+ component: Post,
+ fetchInitialData: (auth, path) => Post.fetchInitialData(auth, path),
},
- { path: `/post/:id`, component: Post },
{
path: `/c/:name/data_type/:data_type/sort/:sort/page/:page`,
component: Community,
{
path: `/u/:username/view/:view/sort/:sort/page/:page`,
component: User,
+ fetchInitialData: (auth, path) => User.fetchInitialData(auth, path),
+ },
+ {
+ path: `/user/:id`,
+ component: User,
+ fetchInitialData: (auth, path) => User.fetchInitialData(auth, path),
+ },
+ {
+ path: `/u/:username`,
+ component: User,
+ fetchInitialData: (auth, path) => User.fetchInitialData(auth, path),
+ },
+ {
+ path: `/inbox`,
+ component: Inbox,
+ fetchInitialData: (auth, path) => Inbox.fetchInitialData(auth, path),
},
- { path: `/user/:id`, component: User },
- { path: `/u/:username`, component: User },
- { path: `/inbox`, component: Inbox },
{
path: `/modlog/community/:community_id`,
component: Modlog,
public login(res: LoginResponse) {
this.setClaims(res.jwt);
- IsomorphicCookie.save('jwt', res.jwt, { expires: 365 });
+ let expires = new Date();
+ expires.setDate(expires.getDate() + 365);
+ IsomorphicCookie.save('jwt', res.jwt, { expires });
console.log('jwt cookie set');
}
: 1;
}
+export function getIdFromProps(props: any): number {
+ return Number(props.match.params.id);
+}
+
+export function getCommentIdFromProps(props: any): number {
+ return Number(props.match.params.comment_id);
+}
+
+export function getUsernameFromProps(props: any): string {
+ return props.match.params.username;
+}
+
export function editCommentRes(data: CommentResponse, comments: Comment[]) {
let found = comments.find(c => c.id == data.comment.id);
if (found) {