Add items to profile menu for setting up paid subscription

This commit is contained in:
silverpill 2022-01-27 18:08:46 +00:00
parent dbfb707dbb
commit 73f7a3c358
2 changed files with 148 additions and 5 deletions

51
src/api/subscriptions.ts Normal file
View file

@ -0,0 +1,51 @@
import { Signer } from "ethers"
import { TransactionResponse } from "@ethersproject/abstract-provider"
import { BACKEND_URL } from "@/constants"
import { Signature } from "@/utils/ethereum"
import { http } from "./common"
import { getContract } from "./contracts"
export async function getSubscriptionAuthorization(
authToken: string,
): Promise<Signature> {
const url = `${BACKEND_URL}/api/v1/accounts/authorize_subscription`
const response = await http(url, {
method: "GET",
authToken,
})
const data = await response.json()
if (response.status !== 200) {
throw new Error(data.message)
} else {
return data
}
}
export async function configureSubscription(
contractName: string,
contractAddress: string,
signer: Signer,
recipientAddress: string,
serverSignature: Signature,
): Promise<TransactionResponse> {
const adapter = await getContract(contractName, contractAddress, signer)
const transaction = await adapter.configureSubscription(
recipientAddress,
serverSignature.v,
"0x" + serverSignature.r,
"0x" + serverSignature.s,
)
return transaction
}
export async function isSubscriptionConfigured(
contractName: string,
contractAddress: string,
signer: Signer,
recipientAddress: string,
): Promise<boolean> {
const adapter = await getContract(contractName, contractAddress, signer)
const result = await adapter.isSubscriptionConfigured(recipientAddress)
return result
}

View file

@ -11,7 +11,7 @@
<div class="badge" v-if="isFollowedBy()">Follows you</div> <div class="badge" v-if="isFollowedBy()">Follows you</div>
</div> </div>
<div <div
v-if="!isLocalUser()" v-if="!isLocalUser() || canConnectWallet() || canConfigureSubscription()"
class="dropdown-menu-wrapper" class="dropdown-menu-wrapper"
v-click-away="hideProfileMenu" v-click-away="hideProfileMenu"
> >
@ -19,9 +19,8 @@
<img :src="require('@/assets/feather/more-vertical.svg')"> <img :src="require('@/assets/feather/more-vertical.svg')">
</button> </button>
<ul v-if="profileMenuVisible" class="dropdown-menu"> <ul v-if="profileMenuVisible" class="dropdown-menu">
<li> <li v-if="!isLocalUser()">
<a <a
v-if="!isLocalUser()"
title="Open profile page" title="Open profile page"
:href="profile.url" :href="profile.url"
target="_blank" target="_blank"
@ -31,6 +30,22 @@
Open profile page Open profile page
</a> </a>
</li> </li>
<li v-if="canConnectWallet()">
<a
title="Connect wallet"
@click="hideProfileMenu(); connectWallet()"
>
Connect wallet
</a>
</li>
<li v-if="canConfigureSubscription()">
<a
title="Set up subscription"
@click="hideProfileMenu(); configureSubscription()"
>
Set up subscription
</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -111,12 +126,18 @@ import {
getFollowers, getFollowers,
getFollowing, getFollowing,
} from "@/api/relationships" } from "@/api/relationships"
import {
getSubscriptionAuthorization,
configureSubscription,
isSubscriptionConfigured,
} from "@/api/subscriptions"
import Avatar from "@/components/Avatar.vue" import Avatar from "@/components/Avatar.vue"
import PostList from "@/components/PostList.vue" import PostList from "@/components/PostList.vue"
import ProfileListItem from "@/components/ProfileListItem.vue" import ProfileListItem from "@/components/ProfileListItem.vue"
import Sidebar from "@/components/Sidebar.vue" import Sidebar from "@/components/Sidebar.vue"
import { useInstanceInfo } from "@/store/instance" import { useInstanceInfo } from "@/store/instance"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
import { getSigner } from "@/utils/ethereum"
@Options({ @Options({
components: { components: {
@ -130,13 +151,16 @@ export default class ProfileView extends Vue {
private store = setup(() => { private store = setup(() => {
const { currentUser, authToken, ensureAuthToken } = useCurrentUser() const { currentUser, authToken, ensureAuthToken } = useCurrentUser()
const { getActorAddress } = useInstanceInfo() const { instance, getActorAddress } = useInstanceInfo()
return { currentUser, authToken, ensureAuthToken, getActorAddress } return { currentUser, authToken, ensureAuthToken, instance, getActorAddress }
}) })
profile: Profile | null = null profile: Profile | null = null
relationship: Relationship | null = null relationship: Relationship | null = null
walletConnected = false
subscriptionConfigured: boolean | null = null
profileMenuVisible = false profileMenuVisible = false
tabName = "posts" tabName = "posts"
@ -250,6 +274,74 @@ export default class ProfileView extends Vue {
return this.profile.username === this.profile.acct return this.profile.username === this.profile.acct
} }
canConnectWallet(): boolean {
return Boolean(this.store.instance?.blockchain_contract_address) && !this.walletConnected
}
async connectWallet() {
const signer = await getSigner()
if (!signer) {
return
}
this.walletConnected = true
this.checkSubscriptionConfigured()
}
canConfigureSubscription(): boolean {
// If wallet is not connected, subscriptionConfigured is set to null
return this.isCurrentUser() && this.subscriptionConfigured === false
}
private async checkSubscriptionConfigured() {
const { instance } = this.store
if (
!this.profile ||
!this.profile.wallet_address ||
!instance ||
!instance.blockchain_contract_name ||
!instance.blockchain_contract_address
) {
return
}
const signer = await getSigner()
if (!signer) {
return
}
this.subscriptionConfigured = await isSubscriptionConfigured(
instance.blockchain_contract_name,
instance.blockchain_contract_address,
signer,
this.profile.wallet_address,
)
}
async configureSubscription() {
const { currentUser, instance } = this.store
if (
!currentUser ||
!instance ||
!instance.blockchain_contract_name ||
!instance.blockchain_contract_address
) {
return
}
// Subscription configuration tx can be send from any address
const signer = await getSigner()
if (!signer) {
return
}
const authToken = this.store.ensureAuthToken()
const signature = await getSubscriptionAuthorization(authToken)
await configureSubscription(
instance.blockchain_contract_name,
instance.blockchain_contract_address,
signer,
currentUser.wallet_address,
signature,
)
this.subscriptionConfigured = true
}
async loadNextPage(maxId: string) { async loadNextPage(maxId: string) {
if (!this.profile) { if (!this.profile) {
return return