diff --git a/src/app/backend-api.service.ts b/src/app/backend-api.service.ts index 12c38c21b..3aeaa8533 100644 --- a/src/app/backend-api.service.ts +++ b/src/app/backend-api.service.ts @@ -180,6 +180,7 @@ export class PostEntryResponse { InMempool: boolean; IsPinned: boolean; DiamondsFromSender?: number; + IsGlobalPinned: boolean; } export class DiamondsPost { @@ -651,6 +652,7 @@ export class BackendApiService { PostExtraData: any, Sub: string, IsHidden: boolean, + IsPinned: boolean, MinFeeRateNanosPerKB: number ): Observable { const request = this.post(endpoint, BackendRoutes.RoutePathSubmitPost, { @@ -663,6 +665,7 @@ export class BackendApiService { PostExtraData, Sub, IsHidden, + IsPinned, MinFeeRateNanosPerKB, }); @@ -778,7 +781,8 @@ export class BackendApiService { ReaderPublicKeyBase58Check: string, LastPostHashHex: string, NumToFetch: number, - MediaRequired: boolean + MediaRequired: boolean, + MaxPinnedPosts: number, ): Observable { return this.post(endpoint, BackendRoutes.RoutePathGetPostsForPublicKey, { PublicKeyBase58Check, @@ -787,6 +791,7 @@ export class BackendApiService { LastPostHashHex, NumToFetch, MediaRequired, + MaxPinnedPosts, }); } diff --git a/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.html b/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.html index b82282604..08ea26ca0 100644 --- a/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.html +++ b/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.html @@ -20,9 +20,11 @@ *ngIf="post.ProfileEntryResponse" [contentShouldLinkToThread]="true" [includePaddingOnPost]="true" + [includeVisualPin]="true" [post]="post" [afterCommentCreatedCallback]="_prependComment.bind(this, post, index)" [blocked]="globalVars.hasUserBlockedCreator(profile.PublicKeyBase58Check)" + [showLeftSelectedBorder]="post.IsPinned" (userBlocked)="userBlocked()" >
diff --git a/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.ts b/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.ts index 6ff48b0a2..5bb6defc1 100644 --- a/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.ts +++ b/src/app/creator-profile-page/creator-profile-posts/creator-profile-posts.component.ts @@ -13,6 +13,7 @@ import * as _ from "lodash"; }) export class CreatorProfilePostsComponent { static PAGE_SIZE = 10; + static MAX_PINNED_POSTS = 5; @Input() profile: ProfileEntryResponse; @Input() afterCommentCreatedCallback: any = null; @Input() showProfileAsReserved: boolean; @@ -104,7 +105,8 @@ export class CreatorProfilePostsComponent { this.globalVars.loggedInUser?.PublicKeyBase58Check, lastPostHashHex, CreatorProfilePostsComponent.PAGE_SIZE, - false /*MediaRequired*/ + false /*MediaRequired*/, + CreatorProfilePostsComponent.MAX_PINNED_POSTS, ) .toPromise() .then((res) => { diff --git a/src/app/feed/feed-create-post/feed-create-post.component.ts b/src/app/feed/feed-create-post/feed-create-post.component.ts index 282119e41..8b87bdf49 100644 --- a/src/app/feed/feed-create-post/feed-create-post.component.ts +++ b/src/app/feed/feed-create-post/feed-create-post.component.ts @@ -171,6 +171,7 @@ export class FeedCreatePostComponent implements OnInit { // TODO: Should we have different values for creator basis points and stake multiple? // TODO: Also, it may not be reasonable to allow stake multiple to be set in the FE. false /*IsHidden*/, + false, this.globalVars.defaultFeeRateNanosPerKB /*MinFeeRateNanosPerKB*/ ) .subscribe( diff --git a/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.html b/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.html index 6ae68b8cd..b91943b25 100644 --- a/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.html +++ b/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.html @@ -5,7 +5,7 @@ - diff --git a/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.ts b/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.ts index 7ba60563e..bd5fab6d2 100644 --- a/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.ts +++ b/src/app/feed/feed-post-dropdown/feed-post-dropdown.component.ts @@ -16,7 +16,8 @@ export class FeedPostDropdownComponent { @Output() postHidden = new EventEmitter(); @Output() userBlocked = new EventEmitter(); @Output() toggleGlobalFeed = new EventEmitter(); - @Output() togglePostPin = new EventEmitter(); + @Output() toggleFeedPostPin = new EventEmitter(); + @Output() toggleProfilePostPin = new EventEmitter(); constructor( public globalVars: GlobalVarsService, @@ -70,11 +71,21 @@ export class FeedPostDropdownComponent { } showPinPostToGlobalFeedDropdownItem(): boolean { - return this.globalFeedEligible() && !this.post.IsPinned; + return this.globalFeedEligible() && !this.post.IsGlobalPinned; } showUnpinPostFromGlobalFeedDropdownItem(): boolean { - return this.globalFeedEligible() && this.post.IsPinned; + return this.globalFeedEligible() && this.post.IsGlobalPinned; + } + + showPinToProfileDropdownItem(): boolean { + return this.globalVars.loggedInUser.PublicKeyBase58Check == this.post.PosterPublicKeyBase58Check + && !this.post.IsPinned; + } + + showUnpinFromProfileDropdownItem(): boolean { + return this.globalVars.loggedInUser.PublicKeyBase58Check == this.post.PosterPublicKeyBase58Check + && this.post.IsPinned; } hidePost() { @@ -90,7 +101,11 @@ export class FeedPostDropdownComponent { } _pinPostToGlobalFeed(event: any) { - this.togglePostPin.emit(event); + this.toggleFeedPostPin.emit(event); + } + + _pinPostToProfile(event: any) { + this.toggleProfilePostPin.emit(event); } copyPostLinkToClipboard(event) { diff --git a/src/app/feed/feed-post-icon-row/feed-post-icon-row.component.ts b/src/app/feed/feed-post-icon-row/feed-post-icon-row.component.ts index 8ce4abf75..654656cf4 100644 --- a/src/app/feed/feed-post-icon-row/feed-post-icon-row.component.ts +++ b/src/app/feed/feed-post-icon-row/feed-post-icon-row.component.ts @@ -122,6 +122,7 @@ export class FeedPostIconRowComponent { {}, "" /*Sub*/, false /*IsHidden*/, + false, // What should the fee rate be for this? this.globalVars.feeRateBitCloutPerKB * 1e9 /*feeRateNanosPerKB*/ ) @@ -171,6 +172,7 @@ export class FeedPostIconRowComponent { {}, "" /*Sub*/, true /*IsHidden*/, + false, // What should the fee rate be for this? this.globalVars.feeRateBitCloutPerKB * 1e9 /*feeRateNanosPerKB*/ ) diff --git a/src/app/feed/feed-post/feed-post.component.html b/src/app/feed/feed-post/feed-post.component.html index 0e1367322..d35fb5dd8 100644 --- a/src/app/feed/feed-post/feed-post.component.html +++ b/src/app/feed/feed-post/feed-post.component.html @@ -180,6 +180,10 @@ [followedPubKeyBase58Check]="postContent.ProfileEntryResponse.PublicKeyBase58Check" > + + + +
diff --git a/src/app/feed/feed-post/feed-post.component.ts b/src/app/feed/feed-post/feed-post.component.ts index 2b68b4200..fb0c1b421 100644 --- a/src/app/feed/feed-post/feed-post.component.ts +++ b/src/app/feed/feed-post/feed-post.component.ts @@ -87,11 +87,14 @@ export class FeedPostComponent implements OnInit { @Input() showReplyingTo = false; + @Input() includeVisualPin = false; + // If the post is shown in a modal, this is used to hide the modal on post click. @Input() containerModalRef: any = null; // emits the PostEntryResponse @Output() postDeleted = new EventEmitter(); + @Output() postPinnedToProfile = new EventEmitter(); // emits the UserBlocked event @Output() userBlocked = new EventEmitter(); @@ -231,13 +234,14 @@ export class FeedPostComponent implements OnInit { this.globalVars.localNode, this.globalVars.loggedInUser.PublicKeyBase58Check, this._post.PostHashHex /*PostHashHexToModify*/, - "" /*ParentPostHashHex*/, + this._post.ParentStakeID /*ParentPostHashHex*/, "" /*Title*/, { Body: this._post.Body, ImageURLs: this._post.ImageURLs } /*BodyObj*/, this._post.RecloutedPostEntryResponse?.PostHashHex || "", {}, "" /*Sub*/, true /*IsHidden*/, + this._post.IsPinned, this.globalVars.feeRateBitCloutPerKB * 1e9 /*feeRateNanosPerKB*/ ) .subscribe( @@ -256,6 +260,37 @@ export class FeedPostComponent implements OnInit { }); } + pinPostToProfile() { + this.backendApi + .SubmitPost( + this.globalVars.localNode, + this.globalVars.loggedInUser.PublicKeyBase58Check, + this._post.PostHashHex /*PostHashHexToModify*/, + this._post.ParentStakeID /*ParentPostHashHex*/, + "" /*Title*/, + { Body: this._post.Body, ImageURLs: this._post.ImageURLs } /*BodyObj*/, + this._post.RecloutedPostEntryResponse?.PostHashHex || "", + {}, + "" /*Sub*/, + this._post.IsHidden /*IsHidden*/, + !this._post.IsPinned, /* We toggle whatever is set already */ + this.globalVars.feeRateBitCloutPerKB * 1e9 /*feeRateNanosPerKB*/ + ) + .subscribe( + (response) => { + this._post.IsPinned = !this._post.IsPinned + this.globalVars.logEvent("post : profile-pin"); + }, + (err) => { + console.error(err); + const parsedError = this.backendApi.parsePostError(err); + this.globalVars.logEvent("post : profile-pin : error", { parsedError }); + this.globalVars._alertError(parsedError); + } + ); + } + + blockUser() { SwalHelper.fire({ target: this.globalVars.getTargetComponentSelector(), diff --git a/src/app/feed/feed.component.html b/src/app/feed/feed.component.html index 0d54be9db..f97879049 100644 --- a/src/app/feed/feed.component.html +++ b/src/app/feed/feed.component.html @@ -56,7 +56,7 @@ [showReplyingToContent]="!!post.parentPost" [parentPost]="post.parentPost" [contentShouldLinkToThread]="true" - [showLeftSelectedBorder]="post.IsPinned" + [showLeftSelectedBorder]="post.IsGlobalPinned" [blocked]="globalVars.hasUserBlockedCreator(post.PosterPublicKeyBase58Check)" (postDeleted)="onPostHidden($event)" (userBlocked)="userBlocked()" diff --git a/src/app/post-thread-page/post-thread/post-thread.component.html b/src/app/post-thread-page/post-thread/post-thread.component.html index d9f0fee24..676211f27 100644 --- a/src/app/post-thread-page/post-thread/post-thread.component.html +++ b/src/app/post-thread-page/post-thread/post-thread.component.html @@ -35,6 +35,7 @@