Split subscription page into two components
This commit is contained in:
parent
4d6ff7b386
commit
c5cf53a1be
5 changed files with 466 additions and 354 deletions
202
src/components/Subscription.vue
Normal file
202
src/components/Subscription.vue
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
<template>
|
||||||
|
<div class="subscription">
|
||||||
|
<h1>Subscription</h1>
|
||||||
|
<div class="connect-wallet" v-if="canConnectWallet()">
|
||||||
|
<button class="btn" @click="connectWallet()">Connect wallet</button>
|
||||||
|
</div>
|
||||||
|
<div class="wallet-error" v-if="walletError">
|
||||||
|
{{ walletError }}
|
||||||
|
</div>
|
||||||
|
<div class="info" v-if="subscriptionConfigured !== null">
|
||||||
|
<template v-if="subscription">
|
||||||
|
<div>Recipient address: {{ subscription.recipientAddress }}</div>
|
||||||
|
<div>Token address: {{ subscription.tokenAddress }}</div>
|
||||||
|
<div>Token symbol: {{ subscription.tokenSymbol }}</div>
|
||||||
|
<div>Price of one month: {{ subscription.price }}</div>
|
||||||
|
<template v-if="subscriptionState">
|
||||||
|
<div>Your address: {{ subscriptionState.senderAddress }}</div>
|
||||||
|
<div>Your balance: {{ subscriptionState.senderBalance }}</div>
|
||||||
|
<div>Expires at: {{ subscription.getExpirationDate(subscriptionState.senderBalance).toLocaleString() }}</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Subscription is not available.
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="payment" v-if="canSubscribe()">
|
||||||
|
<button class="btn" @click="onMakeSubscriptionPayment()">
|
||||||
|
Pay for subscription
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="cancel" v-if="canCancel()">
|
||||||
|
<button class="btn" @click="onCancelSubscription()">
|
||||||
|
Cancel subscription
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { $, $ref } from "vue/macros"
|
||||||
|
|
||||||
|
import { getVerifiedEthereumAddress, Profile } from "@/api/users"
|
||||||
|
import {
|
||||||
|
cancelSubscription,
|
||||||
|
getSubscriptionInfo,
|
||||||
|
getSubscriptionState,
|
||||||
|
makeSubscriptionPayment,
|
||||||
|
Subscription,
|
||||||
|
SubscriptionState,
|
||||||
|
} from "@/api/subscriptions"
|
||||||
|
import { useWallet } from "@/composables/wallet"
|
||||||
|
import { useInstanceInfo } from "@/store/instance"
|
||||||
|
import { ethereumAddressMatch, getWeb3Provider } from "@/utils/ethereum"
|
||||||
|
|
||||||
|
/* eslint-disable-next-line no-undef */
|
||||||
|
const props = defineProps<{
|
||||||
|
profile: Profile,
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { instance } = $(useInstanceInfo())
|
||||||
|
const { connectWallet: connectEthereumWallet } = useWallet()
|
||||||
|
const recipientEthereumAddress = getVerifiedEthereumAddress(props.profile)
|
||||||
|
let { walletAddress, walletError } = $(useWallet())
|
||||||
|
let subscriptionConfigured = $ref<boolean | null>(null)
|
||||||
|
let subscription = $ref<Subscription | null>(null)
|
||||||
|
let subscriptionState = $ref<SubscriptionState | null>(null)
|
||||||
|
|
||||||
|
function canConnectWallet(): boolean {
|
||||||
|
return (
|
||||||
|
Boolean(instance?.blockchain_id) &&
|
||||||
|
Boolean(instance?.blockchain_contract_address) &&
|
||||||
|
// Only profiles with verified address can have subscription
|
||||||
|
recipientEthereumAddress !== null &&
|
||||||
|
walletAddress === null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
subscriptionConfigured = null
|
||||||
|
subscription = null
|
||||||
|
subscriptionState = null
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connectWallet() {
|
||||||
|
await connectEthereumWallet(reset)
|
||||||
|
if (!recipientEthereumAddress || !walletAddress) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (ethereumAddressMatch(walletAddress, recipientEthereumAddress)) {
|
||||||
|
walletError = "incorrect wallet address"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
checkSubscription()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkSubscription() {
|
||||||
|
if (
|
||||||
|
!instance?.blockchain_contract_address ||
|
||||||
|
!recipientEthereumAddress ||
|
||||||
|
!walletAddress
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
subscription = await getSubscriptionInfo(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
recipientEthereumAddress,
|
||||||
|
)
|
||||||
|
if (subscription !== null) {
|
||||||
|
subscriptionConfigured = true
|
||||||
|
} else {
|
||||||
|
subscriptionConfigured = false
|
||||||
|
}
|
||||||
|
subscriptionState = await getSubscriptionState(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
walletAddress,
|
||||||
|
recipientEthereumAddress,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function canSubscribe(): boolean {
|
||||||
|
return subscriptionConfigured === true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onMakeSubscriptionPayment() {
|
||||||
|
if (
|
||||||
|
!instance?.blockchain_contract_address ||
|
||||||
|
!recipientEthereumAddress ||
|
||||||
|
!walletAddress
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
const transaction = await makeSubscriptionPayment(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
recipientEthereumAddress,
|
||||||
|
)
|
||||||
|
await transaction.wait()
|
||||||
|
subscriptionState = await getSubscriptionState(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
walletAddress,
|
||||||
|
recipientEthereumAddress,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function canCancel(): boolean {
|
||||||
|
return (
|
||||||
|
subscriptionState !== null &&
|
||||||
|
!subscriptionState.senderBalance.isZero()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onCancelSubscription() {
|
||||||
|
if (
|
||||||
|
!instance?.blockchain_contract_address ||
|
||||||
|
!recipientEthereumAddress ||
|
||||||
|
!walletAddress
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
const transaction = await cancelSubscription(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
recipientEthereumAddress,
|
||||||
|
)
|
||||||
|
await transaction.wait()
|
||||||
|
subscriptionState = await getSubscriptionState(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
walletAddress,
|
||||||
|
recipientEthereumAddress,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/layout";
|
||||||
|
@import "../styles/mixins";
|
||||||
|
@import "../styles/theme";
|
||||||
|
|
||||||
|
.subscription {
|
||||||
|
@include block-btn;
|
||||||
|
|
||||||
|
background-color: $block-background-color;
|
||||||
|
border-radius: $block-border-radius;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $block-inner-padding / 2;
|
||||||
|
margin-bottom: $block-outer-padding;
|
||||||
|
padding: $block-inner-padding;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
221
src/components/SubscriptionSetup.vue
Normal file
221
src/components/SubscriptionSetup.vue
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
<template>
|
||||||
|
<div class="subscription">
|
||||||
|
<h1>Configure subscription</h1>
|
||||||
|
<div class="connect-wallet" v-if="canConnectWallet()">
|
||||||
|
<button class="btn" @click="connectWallet()">Connect wallet</button>
|
||||||
|
</div>
|
||||||
|
<div class="wallet-error" v-if="walletError">
|
||||||
|
{{ walletError }}
|
||||||
|
</div>
|
||||||
|
<div class="info" v-if="subscriptionConfigured !== null">
|
||||||
|
<template v-if="subscription">
|
||||||
|
<div>Recipient address: {{ subscription.recipientAddress }}</div>
|
||||||
|
<div>Token address: {{ subscription.tokenAddress }}</div>
|
||||||
|
<div>Token symbol: {{ subscription.tokenSymbol }}</div>
|
||||||
|
<div>Price of one month: {{ subscription.price }}</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Subscription is not configured.
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="setup" v-if="canConfigureSubscription()">
|
||||||
|
<button class="btn" @click="onConfigureSubscription()">
|
||||||
|
Set up subscription
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="withdraw" v-if="subscription !== null">
|
||||||
|
<input v-model="subscriberAddress" placeholder="Subscriber address">
|
||||||
|
<button class="btn" @click="onCheckSubsciptionState()">Check</button>
|
||||||
|
<button class="btn" v-if="subscriptionState !== null" @click="onWithdrawReceived()">
|
||||||
|
Withdraw {{ subscriptionState.recipientBalance }} {{ subscription.tokenSymbol }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { $, $ref } from "vue/macros"
|
||||||
|
|
||||||
|
import { getVerifiedEthereumAddress, Profile } from "@/api/users"
|
||||||
|
import {
|
||||||
|
configureSubscription,
|
||||||
|
getSubscriptionAuthorization,
|
||||||
|
getSubscriptionInfo,
|
||||||
|
getSubscriptionState,
|
||||||
|
withdrawReceived,
|
||||||
|
Subscription,
|
||||||
|
SubscriptionState,
|
||||||
|
} from "@/api/subscriptions"
|
||||||
|
import { useWallet } from "@/composables/wallet"
|
||||||
|
import { useInstanceInfo } from "@/store/instance"
|
||||||
|
import { useCurrentUser } from "@/store/user"
|
||||||
|
import { ethereumAddressMatch, getWeb3Provider } from "@/utils/ethereum"
|
||||||
|
|
||||||
|
/* eslint-disable-next-line no-undef */
|
||||||
|
const props = defineProps<{
|
||||||
|
profile: Profile,
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { currentUser, ensureAuthToken } = $(useCurrentUser())
|
||||||
|
const { instance } = $(useInstanceInfo())
|
||||||
|
const { connectWallet: connectEthereumWallet } = useWallet()
|
||||||
|
const profileEthereumAddress = getVerifiedEthereumAddress(props.profile)
|
||||||
|
let { walletAddress, walletError } = $(useWallet())
|
||||||
|
let subscriptionConfigured = $ref<boolean | null>(null)
|
||||||
|
let subscription = $ref<Subscription | null>(null)
|
||||||
|
let subscriptionState = $ref<SubscriptionState | null>(null)
|
||||||
|
let subscriberAddress = $ref<string | null>(null)
|
||||||
|
|
||||||
|
function canConnectWallet(): boolean {
|
||||||
|
return (
|
||||||
|
Boolean(instance?.blockchain_id) &&
|
||||||
|
Boolean(instance?.blockchain_contract_address) &&
|
||||||
|
// Only profiles with verified address can have subscription
|
||||||
|
profileEthereumAddress !== null &&
|
||||||
|
walletAddress === null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
subscriptionConfigured = null
|
||||||
|
subscription = null
|
||||||
|
subscriptionState = null
|
||||||
|
subscriberAddress = null
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connectWallet() {
|
||||||
|
await connectEthereumWallet(reset)
|
||||||
|
if (!profileEthereumAddress || !walletAddress) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!ethereumAddressMatch(walletAddress, profileEthereumAddress)) {
|
||||||
|
// Recipient must use verified account
|
||||||
|
walletError = "incorrect wallet address"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
checkSubscription()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkSubscription() {
|
||||||
|
if (
|
||||||
|
!profileEthereumAddress ||
|
||||||
|
!instance ||
|
||||||
|
!instance.blockchain_contract_address
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
subscription = await getSubscriptionInfo(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
profileEthereumAddress,
|
||||||
|
)
|
||||||
|
if (subscription !== null) {
|
||||||
|
subscriptionConfigured = true
|
||||||
|
} else {
|
||||||
|
subscriptionConfigured = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function canConfigureSubscription(): boolean {
|
||||||
|
return (
|
||||||
|
Boolean(currentUser?.wallet_address) &&
|
||||||
|
subscriptionConfigured === false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onConfigureSubscription() {
|
||||||
|
if (
|
||||||
|
!currentUser ||
|
||||||
|
!currentUser.wallet_address ||
|
||||||
|
!instance ||
|
||||||
|
!instance.blockchain_contract_address
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Subscription configuration tx can be sent from any address
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
const authToken = ensureAuthToken()
|
||||||
|
const signature = await getSubscriptionAuthorization(authToken)
|
||||||
|
const transaction = await configureSubscription(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
currentUser.wallet_address,
|
||||||
|
signature,
|
||||||
|
)
|
||||||
|
await transaction.wait()
|
||||||
|
subscriptionConfigured = true
|
||||||
|
subscription = await getSubscriptionInfo(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
currentUser.wallet_address,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onCheckSubsciptionState() {
|
||||||
|
if (
|
||||||
|
!profileEthereumAddress ||
|
||||||
|
!instance?.blockchain_contract_address ||
|
||||||
|
!subscriberAddress
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
subscriptionState = await getSubscriptionState(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
subscriberAddress,
|
||||||
|
profileEthereumAddress,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onWithdrawReceived() {
|
||||||
|
if (
|
||||||
|
!instance?.blockchain_contract_address ||
|
||||||
|
!subscriberAddress
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const signer = getWeb3Provider().getSigner()
|
||||||
|
await withdrawReceived(
|
||||||
|
instance.blockchain_contract_address,
|
||||||
|
signer,
|
||||||
|
subscriberAddress,
|
||||||
|
)
|
||||||
|
subscriptionState = null
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/layout";
|
||||||
|
@import "../styles/mixins";
|
||||||
|
@import "../styles/theme";
|
||||||
|
|
||||||
|
.subscription {
|
||||||
|
@include block-btn;
|
||||||
|
|
||||||
|
background-color: $block-background-color;
|
||||||
|
border-radius: $block-border-radius;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $block-inner-padding / 2;
|
||||||
|
margin-bottom: $block-outer-padding;
|
||||||
|
padding: $block-inner-padding;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.withdraw {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: $block-inner-padding / 2;
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 1px solid $btn-background-hover-color;
|
||||||
|
border-radius: $btn-border-radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -13,7 +13,7 @@ import PostOverlay from "@/views/PostOverlay.vue"
|
||||||
import PublicTimeline from "@/views/PublicTimeline.vue"
|
import PublicTimeline from "@/views/PublicTimeline.vue"
|
||||||
import TagTimeline from "@/views/TagTimeline.vue"
|
import TagTimeline from "@/views/TagTimeline.vue"
|
||||||
import SearchResultList from "@/views/SearchResultList.vue"
|
import SearchResultList from "@/views/SearchResultList.vue"
|
||||||
import SubscriptionView from "@/views/Subscription.vue"
|
import SubscriptionPage from "@/views/SubscriptionPage.vue"
|
||||||
|
|
||||||
import { useCurrentUser } from "@/store/user"
|
import { useCurrentUser } from "@/store/user"
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||||
{
|
{
|
||||||
path: "/profile/:profileId/subscription",
|
path: "/profile/:profileId/subscription",
|
||||||
name: "profile-subscription",
|
name: "profile-subscription",
|
||||||
component: SubscriptionView,
|
component: SubscriptionPage,
|
||||||
meta: { },
|
meta: { },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,352 +0,0 @@
|
||||||
<template>
|
|
||||||
<div id="main" v-if="profile">
|
|
||||||
<div class="content subscription">
|
|
||||||
<h1>
|
|
||||||
Subscription: @{{ getActorAddress(profile) }}
|
|
||||||
</h1>
|
|
||||||
<div class="connect-wallet" v-if="canConnectWallet()">
|
|
||||||
<button class="btn" @click="connectWallet()">Connect wallet</button>
|
|
||||||
</div>
|
|
||||||
<div class="wallet-error" v-if="walletError">
|
|
||||||
{{ walletError }}
|
|
||||||
</div>
|
|
||||||
<div class="info" v-if="subscriptionConfigured !== null">
|
|
||||||
<template v-if="subscription">
|
|
||||||
<div>Recipient address: {{ subscription.recipientAddress }}</div>
|
|
||||||
<div>Token address: {{ subscription.tokenAddress }}</div>
|
|
||||||
<div>Token symbol: {{ subscription.tokenSymbol }}</div>
|
|
||||||
<div>Price of one month: {{ subscription.price }}</div>
|
|
||||||
<template v-if="!isRecipient() && subscriptionState">
|
|
||||||
<div>Your address: {{ subscriptionState.senderAddress }}</div>
|
|
||||||
<div>Your balance: {{ subscriptionState.senderBalance }}</div>
|
|
||||||
<div>Expires at: {{ subscription.getExpirationDate(subscriptionState.senderBalance).toLocaleString() }}</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="isCurrentUser()">
|
|
||||||
Subscription is not configured.
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
Subscription is not available.
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="setup" v-if="canConfigureSubscription()">
|
|
||||||
<button class="btn" @click="onConfigureSubscription()">
|
|
||||||
Set up subscription
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="payment" v-if="canSubscribe()">
|
|
||||||
<button class="btn" @click="onMakeSubscriptionPayment()">
|
|
||||||
Pay for subscription
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="cancel" v-if="canCancel()">
|
|
||||||
<button class="btn" @click="onCancelSubscription()">
|
|
||||||
Cancel subscription
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="withdraw" v-if="isRecipient()">
|
|
||||||
<input v-model="subscriberAddress" placeholder="Subscriber address">
|
|
||||||
<button class="btn" @click="onCheckSubsciptionState()">Check</button>
|
|
||||||
<button class="btn" v-if="canWithdrawReceived()" @click="onWithdrawReceived()">
|
|
||||||
Withdraw {{ subscriptionState.recipientBalance }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<sidebar></sidebar>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { onMounted } from "vue"
|
|
||||||
import { $, $ref } from "vue/macros"
|
|
||||||
import { useRoute } from "vue-router"
|
|
||||||
|
|
||||||
import {
|
|
||||||
getProfile,
|
|
||||||
getVerifiedEthereumAddress,
|
|
||||||
Profile,
|
|
||||||
} from "@/api/users"
|
|
||||||
import {
|
|
||||||
cancelSubscription,
|
|
||||||
configureSubscription,
|
|
||||||
getSubscriptionAuthorization,
|
|
||||||
getSubscriptionInfo,
|
|
||||||
getSubscriptionState,
|
|
||||||
makeSubscriptionPayment,
|
|
||||||
withdrawReceived,
|
|
||||||
Subscription,
|
|
||||||
SubscriptionState,
|
|
||||||
} from "@/api/subscriptions"
|
|
||||||
import Sidebar from "@/components/Sidebar.vue"
|
|
||||||
import { useWallet } from "@/composables/wallet"
|
|
||||||
import { useInstanceInfo } from "@/store/instance"
|
|
||||||
import { useCurrentUser } from "@/store/user"
|
|
||||||
import { ethereumAddressMatch, getWeb3Provider } from "@/utils/ethereum"
|
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const { currentUser, ensureAuthToken } = $(useCurrentUser())
|
|
||||||
const { instance, getActorAddress } = $(useInstanceInfo())
|
|
||||||
const { connectWallet: connectEthereumWallet } = useWallet()
|
|
||||||
let { walletAddress, walletError } = $(useWallet())
|
|
||||||
let profile = $ref<Profile | null>(null)
|
|
||||||
let profileEthereumAddress = $ref<string | null>(null)
|
|
||||||
let subscriptionConfigured = $ref<boolean | null>(null)
|
|
||||||
let subscription = $ref<Subscription | null>(null)
|
|
||||||
let subscriptionState = $ref<SubscriptionState | null>(null)
|
|
||||||
let subscriberAddress = $ref<string | null>(null)
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const { authToken } = $(useCurrentUser())
|
|
||||||
profile = await getProfile(
|
|
||||||
authToken,
|
|
||||||
route.params.profileId as string,
|
|
||||||
)
|
|
||||||
profileEthereumAddress = getVerifiedEthereumAddress(profile)
|
|
||||||
})
|
|
||||||
|
|
||||||
function isCurrentUser(): boolean {
|
|
||||||
if (!currentUser || !profile) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return currentUser.id === profile.id
|
|
||||||
}
|
|
||||||
|
|
||||||
function canConnectWallet(): boolean {
|
|
||||||
return (
|
|
||||||
Boolean(instance?.blockchain_id) &&
|
|
||||||
Boolean(instance?.blockchain_contract_address) &&
|
|
||||||
// Only profiles with verified address can have subscription
|
|
||||||
profileEthereumAddress !== null &&
|
|
||||||
walletAddress === null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset() {
|
|
||||||
subscriptionConfigured = null
|
|
||||||
subscription = null
|
|
||||||
subscriptionState = null
|
|
||||||
subscriberAddress = null
|
|
||||||
}
|
|
||||||
|
|
||||||
async function connectWallet() {
|
|
||||||
await connectEthereumWallet(reset)
|
|
||||||
if (!profileEthereumAddress || !walletAddress) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (isCurrentUser() && !ethereumAddressMatch(walletAddress, profileEthereumAddress)) {
|
|
||||||
// Recipient must use verified account
|
|
||||||
walletError = "incorrect wallet address"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!isCurrentUser() && ethereumAddressMatch(walletAddress, profileEthereumAddress)) {
|
|
||||||
walletError = "incorrect wallet address"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
checkSubscription()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkSubscription() {
|
|
||||||
if (
|
|
||||||
!profile ||
|
|
||||||
!profileEthereumAddress ||
|
|
||||||
!instance ||
|
|
||||||
!instance.blockchain_contract_address
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const signer = getWeb3Provider().getSigner()
|
|
||||||
subscription = await getSubscriptionInfo(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
if (subscription !== null) {
|
|
||||||
subscriptionConfigured = true
|
|
||||||
} else {
|
|
||||||
subscriptionConfigured = false
|
|
||||||
}
|
|
||||||
const signerAddress = await signer.getAddress()
|
|
||||||
if (!ethereumAddressMatch(signerAddress, profileEthereumAddress)) {
|
|
||||||
// Connected wallet is a subscriber
|
|
||||||
subscriptionState = await getSubscriptionState(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
signerAddress,
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function canConfigureSubscription(): boolean {
|
|
||||||
return (
|
|
||||||
isCurrentUser() &&
|
|
||||||
Boolean(currentUser?.wallet_address) &&
|
|
||||||
subscriptionConfigured === false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onConfigureSubscription() {
|
|
||||||
if (
|
|
||||||
!currentUser ||
|
|
||||||
!currentUser.wallet_address ||
|
|
||||||
!isCurrentUser() ||
|
|
||||||
!instance ||
|
|
||||||
!instance.blockchain_contract_address
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Subscription configuration tx can be send from any address
|
|
||||||
const signer = getWeb3Provider().getSigner()
|
|
||||||
const authToken = ensureAuthToken()
|
|
||||||
const signature = await getSubscriptionAuthorization(authToken)
|
|
||||||
const transaction = await configureSubscription(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
currentUser.wallet_address,
|
|
||||||
signature,
|
|
||||||
)
|
|
||||||
await transaction.wait()
|
|
||||||
subscriptionConfigured = true
|
|
||||||
subscription = await getSubscriptionInfo(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
currentUser.wallet_address,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function canSubscribe(): boolean {
|
|
||||||
return !isCurrentUser() && subscriptionConfigured === true
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onMakeSubscriptionPayment() {
|
|
||||||
if (
|
|
||||||
!profile ||
|
|
||||||
!profileEthereumAddress ||
|
|
||||||
!instance ||
|
|
||||||
!instance.blockchain_contract_address
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const signer = getWeb3Provider().getSigner()
|
|
||||||
const transaction = await makeSubscriptionPayment(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
await transaction.wait()
|
|
||||||
subscriptionState = await getSubscriptionState(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
await signer.getAddress(),
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function canCancel(): boolean {
|
|
||||||
return (
|
|
||||||
!isCurrentUser() &&
|
|
||||||
subscriptionState !== null &&
|
|
||||||
!subscriptionState.senderBalance.isZero()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onCancelSubscription() {
|
|
||||||
if (
|
|
||||||
!profile ||
|
|
||||||
!profileEthereumAddress ||
|
|
||||||
!instance?.blockchain_contract_address
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const signer = getWeb3Provider().getSigner()
|
|
||||||
const transaction = await cancelSubscription(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
await transaction.wait()
|
|
||||||
subscriptionState = await getSubscriptionState(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
await signer.getAddress(),
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRecipient(): boolean {
|
|
||||||
return isCurrentUser() && subscription !== null
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onCheckSubsciptionState() {
|
|
||||||
if (
|
|
||||||
!profile ||
|
|
||||||
!profileEthereumAddress ||
|
|
||||||
!instance?.blockchain_contract_address ||
|
|
||||||
!subscriberAddress
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const signer = getWeb3Provider().getSigner()
|
|
||||||
subscriptionState = await getSubscriptionState(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
subscriberAddress,
|
|
||||||
profileEthereumAddress,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function canWithdrawReceived(): boolean {
|
|
||||||
return isRecipient() && subscriptionState !== null
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onWithdrawReceived() {
|
|
||||||
if (
|
|
||||||
!profile ||
|
|
||||||
!instance?.blockchain_contract_address ||
|
|
||||||
!subscriberAddress
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const signer = getWeb3Provider().getSigner()
|
|
||||||
await withdrawReceived(
|
|
||||||
instance.blockchain_contract_address,
|
|
||||||
signer,
|
|
||||||
subscriberAddress,
|
|
||||||
)
|
|
||||||
subscriptionState = null
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
@import "../styles/layout";
|
|
||||||
@import "../styles/mixins";
|
|
||||||
@import "../styles/theme";
|
|
||||||
|
|
||||||
.subscription {
|
|
||||||
@include block-btn;
|
|
||||||
|
|
||||||
background-color: $block-background-color;
|
|
||||||
border-radius: $block-border-radius;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $block-inner-padding / 2;
|
|
||||||
margin-bottom: $block-outer-padding;
|
|
||||||
padding: $block-inner-padding;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 20px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.withdraw {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: $block-inner-padding / 2;
|
|
||||||
|
|
||||||
input {
|
|
||||||
border: 1px solid $btn-background-hover-color;
|
|
||||||
border-radius: $btn-border-radius;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
41
src/views/SubscriptionPage.vue
Normal file
41
src/views/SubscriptionPage.vue
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<div id="main" v-if="profile">
|
||||||
|
<div class="content">
|
||||||
|
<component
|
||||||
|
:is="isCurrentUser() ? SubscriptionSetup : Subscription"
|
||||||
|
:profile="profile"
|
||||||
|
></component>
|
||||||
|
</div>
|
||||||
|
<sidebar></sidebar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted } from "vue"
|
||||||
|
import { $, $ref } from "vue/macros"
|
||||||
|
import { useRoute } from "vue-router"
|
||||||
|
|
||||||
|
import { getProfile, Profile } from "@/api/users"
|
||||||
|
import Sidebar from "@/components/Sidebar.vue"
|
||||||
|
import Subscription from "@/components/Subscription.vue"
|
||||||
|
import SubscriptionSetup from "@/components/SubscriptionSetup.vue"
|
||||||
|
import { useCurrentUser } from "@/store/user"
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const { currentUser, authToken } = $(useCurrentUser())
|
||||||
|
let profile = $ref<Profile | null>(null)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
profile = await getProfile(
|
||||||
|
authToken,
|
||||||
|
route.params.profileId as string,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
function isCurrentUser(): boolean {
|
||||||
|
if (!currentUser || !profile) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return currentUser.id === profile.id
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in a new issue