languages,
showAvatars,
toast,
+ editCommentRes,
+ saveCommentRes,
+ createCommentLikeRes,
+ createPostLikeFindRes,
+ commentsToFlatNodes,
+ setupTippy,
} from '../utils';
import { PostListing } from './post-listing';
+import { UserListing } from './user-listing';
import { SortSelect } from './sort-select';
import { ListingTypeSelect } from './listing-type-select';
import { CommentNodes } from './comment-nodes';
user: {
id: null,
name: null,
- fedi_name: null,
published: null,
number_of_posts: null,
post_score: null,
avatar: null,
show_avatars: null,
send_notifications_to_email: null,
+ actor_id: null,
+ local: null,
},
user_id: null,
username: null,
);
}
- selects() {
+ viewRadios() {
return (
- <div className="mb-2">
- <select
- value={this.state.view}
- onChange={linkEvent(this, this.handleViewChange)}
- class="custom-select custom-select-sm w-auto"
+ <div class="btn-group btn-group-toggle">
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Overview && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={View.Overview}
+ checked={this.state.view == View.Overview}
+ onChange={linkEvent(this, this.handleViewChange)}
+ />
+ {i18n.t('overview')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Comments && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={View.Comments}
+ checked={this.state.view == View.Comments}
+ onChange={linkEvent(this, this.handleViewChange)}
+ />
+ {i18n.t('comments')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Posts && 'active'}
+ `}
+ >
+ <input
+ type="radio"
+ value={View.Posts}
+ checked={this.state.view == View.Posts}
+ onChange={linkEvent(this, this.handleViewChange)}
+ />
+ {i18n.t('posts')}
+ </label>
+ <label
+ className={`btn btn-sm btn-secondary pointer btn-outline-light
+ ${this.state.view == View.Saved && 'active'}
+ `}
>
- <option disabled>{i18n.t('view')}</option>
- <option value={View.Overview}>{i18n.t('overview')}</option>
- <option value={View.Comments}>{i18n.t('comments')}</option>
- <option value={View.Posts}>{i18n.t('posts')}</option>
- <option value={View.Saved}>{i18n.t('saved')}</option>
- </select>
- <span class="ml-2">
- <SortSelect
- sort={this.state.sort}
- onChange={this.handleSortChange}
- hideHot
+ <input
+ type="radio"
+ value={View.Saved}
+ checked={this.state.view == View.Saved}
+ onChange={linkEvent(this, this.handleViewChange)}
/>
- </span>
+ {i18n.t('saved')}
+ </label>
+ </div>
+ );
+ }
+
+ selects() {
+ return (
+ <div className="mb-2">
+ <span class="mr-3">{this.viewRadios()}</span>
+ <SortSelect
+ sort={this.state.sort}
+ onChange={this.handleSortChange}
+ hideHot
+ />
<a
href={`/feeds/u/${this.state.username}.xml?sort=${
SortType[this.state.sort]
}`}
target="_blank"
+ title="RSS"
>
<svg class="icon mx-2 text-muted small">
<use xlinkHref="#icon-rss">#</use>
nodes={[{ comment: i.data as Comment }]}
admins={this.state.admins}
noIndent
+ showContext
/>
)}
</div>
comments() {
return (
<div>
- {this.state.comments.map(comment => (
- <CommentNodes
- nodes={[{ comment: comment }]}
- admins={this.state.admins}
- noIndent
- />
- ))}
+ <CommentNodes
+ nodes={commentsToFlatNodes(this.state.comments)}
+ admins={this.state.admins}
+ noIndent
+ showContext
+ />
</div>
);
}
<div class="card-body">
<h5>
<ul class="list-inline mb-0">
- <li className="list-inline-item">{user.name}</li>
+ <li className="list-inline-item">
+ <UserListing user={user} realLink />
+ </li>
{user.banned && (
<li className="list-inline-item badge badge-danger">
{i18n.t('banned')}
</ul>
</h5>
<div>
- {i18n.t('joined')} <MomentTime data={user} />
+ {i18n.t('joined')} <MomentTime data={user} showAgo />
</div>
- <div class="table-responsive">
+ <div class="table-responsive mt-1">
<table class="table table-bordered table-sm mt-2 mb-0">
+ {/*
<tr>
+ <td class="text-center" colSpan={2}>
+ {i18n.t('number_of_points', {
+ count: user.post_score + user.comment_score,
+ })}
+ </td>
+ </tr>
+ */}
+ <tr>
+ {/*
<td>
{i18n.t('number_of_points', { count: user.post_score })}
</td>
+ */}
<td>
{i18n.t('number_of_posts', { count: user.number_of_posts })}
</td>
+ {/*
</tr>
<tr>
<td>
{i18n.t('number_of_points', { count: user.comment_score })}
</td>
+ */}
<td>
{i18n.t('number_of_comments', {
count: user.number_of_comments,
) : (
<>
<a
- className={`btn btn-block btn-secondary mt-3 ${!this.state
- .user.matrix_user_id && 'disabled'}`}
+ className={`btn btn-block btn-secondary mt-3 ${
+ !this.state.user.matrix_user_id && 'disabled'
+ }`}
target="_blank"
href={`https://matrix.to/#/${this.state.user.matrix_user_id}`}
>
id="user-password"
class="form-control"
value={this.state.userSettingsForm.new_password}
+ autoComplete="new-password"
onInput={linkEvent(
this,
this.handleUserSettingsNewPasswordChange
id="user-verify-password"
class="form-control"
value={this.state.userSettingsForm.new_password_verify}
+ autoComplete="new-password"
onInput={linkEvent(
this,
this.handleUserSettingsNewPasswordVerifyChange
id="user-old-password"
class="form-control"
value={this.state.userSettingsForm.old_password}
+ autoComplete="new-password"
onInput={linkEvent(
this,
this.handleUserSettingsOldPasswordChange
<input
type="password"
value={this.state.deleteAccountForm.password}
+ autoComplete="new-password"
onInput={linkEvent(
this,
this.handleDeleteAccountPasswordChange
handleUserSettingsThemeChange(i: User, event: any) {
i.state.userSettingsForm.theme = event.target.value;
- setTheme(event.target.value);
+ setTheme(event.target.value, true);
i.setState(i.state);
}
handleImageUpload(i: User, event: any) {
event.preventDefault();
let file = event.target.files[0];
- const imageUploadUrl = `/pictshare/api/upload.php`;
+ const imageUploadUrl = `/pictrs/image`;
const formData = new FormData();
- formData.append('file', file);
+ formData.append('images[]', file);
i.state.avatarLoading = true;
i.setState(i.state);
})
.then(res => res.json())
.then(res => {
- let url = `${window.location.origin}/pictshare/${res.url}`;
- if (res.filetype == 'mp4') {
- url += '/raw';
+ console.log('pictrs upload:');
+ console.log(res);
+ if (res.msg == 'ok') {
+ let hash = res.files[0].file;
+ let url = `${window.location.origin}/pictrs/image/${hash}`;
+ i.state.userSettingsForm.avatar = url;
+ i.state.avatarLoading = false;
+ i.setState(i.state);
+ } else {
+ i.state.avatarLoading = false;
+ i.setState(i.state);
+ toast(JSON.stringify(res), 'danger');
}
- i.state.userSettingsForm.avatar = url;
- console.log(url);
- i.state.avatarLoading = false;
- i.setState(i.state);
})
.catch(error => {
i.state.avatarLoading = false;
}
this.setState(this.state);
return;
+ } else if (msg.reconnect) {
+ this.refetch();
} else if (res.op == UserOperation.GetUserDetails) {
let data = res.data as UserDetailsResponse;
this.state.user = data.user;
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
window.scrollTo(0, 0);
this.setState(this.state);
+ setupTippy();
} else if (res.op == UserOperation.EditComment) {
let data = res.data as CommentResponse;
-
- let found = this.state.comments.find(c => c.id == data.comment.id);
- found.content = data.comment.content;
- found.updated = data.comment.updated;
- found.removed = data.comment.removed;
- found.deleted = data.comment.deleted;
- found.upvotes = data.comment.upvotes;
- found.downvotes = data.comment.downvotes;
- found.score = data.comment.score;
-
+ editCommentRes(data, this.state.comments);
this.setState(this.state);
} else if (res.op == UserOperation.CreateComment) {
- // let res: CommentResponse = msg;
- toast(i18n.t('reply_sent'));
- // this.state.comments.unshift(res.comment); // TODO do this right
- // this.setState(this.state);
+ let 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) {
let data = res.data as CommentResponse;
- let found = this.state.comments.find(c => c.id == data.comment.id);
- found.saved = data.comment.saved;
+ saveCommentRes(data, this.state.comments);
this.setState(this.state);
} else if (res.op == UserOperation.CreateCommentLike) {
let data = res.data as CommentResponse;
- let found: Comment = this.state.comments.find(
- c => c.id === data.comment.id
- );
- found.score = data.comment.score;
- found.upvotes = data.comment.upvotes;
- found.downvotes = data.comment.downvotes;
- if (data.comment.my_vote !== null) found.my_vote = data.comment.my_vote;
+ createCommentLikeRes(data, this.state.comments);
this.setState(this.state);
} else if (res.op == UserOperation.CreatePostLike) {
let data = res.data as PostResponse;
- let found = this.state.posts.find(c => c.id == data.post.id);
- found.my_vote = data.post.my_vote;
- found.score = data.post.score;
- found.upvotes = data.post.upvotes;
- found.downvotes = data.post.downvotes;
+ createPostLikeFindRes(data, this.state.posts);
this.setState(this.state);
} else if (res.op == UserOperation.BanUser) {
let data = res.data as BanUserResponse;