Add items to profile menu for setting up paid subscription
This commit is contained in:
parent
dbfb707dbb
commit
73f7a3c358
2 changed files with 148 additions and 5 deletions
51
src/api/subscriptions.ts
Normal file
51
src/api/subscriptions.ts
Normal 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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue