Adding loading indicators to save and mark as read. #519

This commit is contained in:
Dessalines 2020-03-19 11:45:23 -04:00
parent ed00fe46e2
commit 47dd8acf54
4 changed files with 95 additions and 63 deletions

View file

@ -56,6 +56,8 @@ interface CommentNodeState {
upvotes: number;
downvotes: number;
borderColor: string;
readLoading: boolean;
saveLoading: boolean;
}
interface CommentNodeProps {
@ -97,6 +99,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
borderColor: this.props.node.comment.depth
? colorList[this.props.node.comment.depth % colorList.length]
: colorList[0],
readLoading: false,
saveLoading: false,
};
constructor(props: any, context: any) {
@ -113,6 +117,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
this.state.upvotes = nextProps.node.comment.upvotes;
this.state.downvotes = nextProps.node.comment.downvotes;
this.state.score = nextProps.node.comment.score;
this.state.readLoading = false;
this.state.saveLoading = false;
this.setState(this.state);
}
@ -255,12 +261,16 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
: i18n.t('mark_as_read')
}
>
<svg
class={`icon icon-inline ${node.comment.read &&
'text-success'}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
{this.state.readLoading ? (
this.loadingIcon
) : (
<svg
class={`icon icon-inline ${node.comment.read &&
'text-success'}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
)}
</button>
</li>
)}
@ -305,6 +315,28 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</button>
</li>
)}
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleSaveCommentClick)}
data-tippy-content={
node.comment.saved
? i18n.t('unsave')
: i18n.t('save')
}
>
{this.state.saveLoading ? (
this.loadingIcon
) : (
<svg
class={`icon icon-inline ${node.comment.saved &&
'text-warning'}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
)}
</button>
</li>
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
@ -316,17 +348,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</svg>
</button>
</li>
<li className="list-inline-item">
<Link
className="btn btn-link btn-sm btn-animate text-muted"
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
title={i18n.t('link')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-link"></use>
</svg>
</Link>
</li>
{this.props.markable && this.linkBtn}
{!this.state.showAdvanced ? (
<li className="list-inline-item">
<button
@ -354,27 +376,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
</Link>
</li>
)}
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(
this,
this.handleSaveCommentClick
)}
data-tippy-content={
node.comment.saved
? i18n.t('unsave')
: i18n.t('save')
}
>
<svg
class={`icon icon-inline ${node.comment.saved &&
'text-warning'}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
</button>
</li>
{!this.props.markable && this.linkBtn}
<li className="list-inline-item">
<button
className="btn btn-link btn-sm btn-animate text-muted"
@ -756,6 +758,31 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
);
}
get linkBtn() {
let node = this.props.node;
return (
<li className="list-inline-item">
<Link
className="btn btn-link btn-sm btn-animate text-muted"
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
title={i18n.t('link')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-link"></use>
</svg>
</Link>
</li>
);
}
get loadingIcon() {
return (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
);
}
get myComment(): boolean {
return (
UserService.Instance.user &&
@ -875,6 +902,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
};
WebSocketService.Instance.saveComment(form);
i.state.saveLoading = true;
i.setState(this.state);
}
handleReplyCancel() {
@ -987,6 +1017,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
};
WebSocketService.Instance.editComment(form);
}
i.state.readLoading = true;
i.setState(this.state);
}
handleModBanFromCommunityShow(i: CommentNode) {

View file

@ -28,8 +28,7 @@ export class PostListings extends Component<PostListingsProps, any> {
post={post}
showCommunity={this.props.showCommunity}
/>
<hr class="d-md-none my-2" />
<div class="d-none d-md-block my-2"></div>
<hr class="my-2" />
</>
))
) : (

View file

@ -211,7 +211,7 @@ export class Post extends Component<any, PostState> {
sortRadios() {
return (
<div class="btn-group btn-group-toggle">
<div class="btn-group btn-group-toggle mb-2">
<label
className={`btn btn-sm btn-secondary pointer ${this.state
.commentSort === CommentSortType.Hot && 'active'}`}

View file

@ -55,7 +55,7 @@ export class PrivateMessage extends Component<
render() {
let message = this.props.privateMessage;
return (
<div class="mb-2">
<div class="border-top border-light">
<div>
<ul class="list-inline mb-0 text-muted small">
<li className="list-inline-item">
@ -129,12 +129,12 @@ export class PrivateMessage extends Component<
dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
/>
)}
<ul class="list-inline mb-1 text-muted h5 font-weight-bold">
<ul class="list-inline mb-0 text-muted font-weight-bold">
{!this.mine && (
<>
<li className="list-inline-item-action">
<span
class="pointer"
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleMarkRead)}
data-tippy-content={
message.read
@ -148,37 +148,37 @@ export class PrivateMessage extends Component<
>
<use xlinkHref="#icon-check"></use>
</svg>
</span>
</button>
</li>
<li className="list-inline-item-action">
<span
class="pointer"
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleReplyClick)}
data-tippy-content={i18n.t('reply')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-reply1"></use>
</svg>
</span>
</button>
</li>
</>
)}
{this.mine && (
<>
<li className="list-inline-item-action">
<span
class="pointer"
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleEditClick)}
data-tippy-content={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
</span>
</button>
</li>
<li className="list-inline-item-action">
<span
class="pointer"
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleDeleteClick)}
data-tippy-content={
!message.deleted
@ -192,13 +192,13 @@ export class PrivateMessage extends Component<
>
<use xlinkHref="#icon-trash"></use>
</svg>
</span>
</button>
</li>
</>
)}
<li className="list-inline-item-action">
<span
className="pointer"
<li className="list-inline-item">
<button
class="btn btn-link btn-sm btn-animate text-muted"
onClick={linkEvent(this, this.handleViewSource)}
data-tippy-content={i18n.t('view_source')}
>
@ -208,7 +208,7 @@ export class PrivateMessage extends Component<
>
<use xlinkHref="#icon-file-text"></use>
</svg>
</span>
</button>
</li>
</ul>
</div>