List subscribers on subscription setup page
This commit is contained in:
parent
7002eea107
commit
5f2506c170
6 changed files with 74 additions and 9 deletions
|
@ -7,7 +7,7 @@ import { ethereumAddressMatch, EthereumSignature } from "@/utils/ethereum"
|
||||||
import { floatToBigNumber, roundBigNumber } from "@/utils/numbers"
|
import { floatToBigNumber, roundBigNumber } from "@/utils/numbers"
|
||||||
import { http } from "./common"
|
import { http } from "./common"
|
||||||
import { Contracts, getContract } from "./contracts"
|
import { Contracts, getContract } from "./contracts"
|
||||||
import { User } from "./users"
|
import { Profile, User } from "./users"
|
||||||
|
|
||||||
const SECONDS_IN_DAY = 3600 * 24
|
const SECONDS_IN_DAY = 3600 * 24
|
||||||
const SECONDS_IN_MONTH = SECONDS_IN_DAY * 30
|
const SECONDS_IN_MONTH = SECONDS_IN_DAY * 30
|
||||||
|
@ -227,6 +227,22 @@ export async function cancelSubscription(
|
||||||
return transaction
|
return transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Subscription {
|
||||||
|
id: number,
|
||||||
|
sender: Profile,
|
||||||
|
sender_address: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSubscribers(
|
||||||
|
authToken: string,
|
||||||
|
accountId: string,
|
||||||
|
): Promise<Subscription[]> {
|
||||||
|
const url = `${BACKEND_URL}/api/v1/accounts/${accountId}/subscribers`
|
||||||
|
const response = await http(url, { authToken })
|
||||||
|
const data = await response.json()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
export async function withdrawReceived(
|
export async function withdrawReceived(
|
||||||
contractAddress: string,
|
contractAddress: string,
|
||||||
signer: Signer,
|
signer: Signer,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<router-link class="profile" :to="{ name: 'profile', params: { profileId: profile.id }}">
|
<div class="profile">
|
||||||
<avatar :profile="profile"></avatar>
|
<avatar :profile="profile"></avatar>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<div class="display-name">{{ profile.display_name || profile.username }}</div>
|
<div class="display-name">{{ profile.display_name || profile.username }}</div>
|
||||||
<div class="actor-address">@{{ getActorAddress(profile) }}</div>
|
<div class="actor-address">@{{ getActorAddress(profile) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -32,19 +32,29 @@ defineProps<{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: $block-inner-padding;
|
padding: $block-inner-padding;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
height: $avatar-size;
|
height: $avatar-size;
|
||||||
margin-right: $block-inner-padding;
|
margin-right: $block-inner-padding;
|
||||||
|
min-width: $avatar-size;
|
||||||
width: $avatar-size;
|
width: $avatar-size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.display-name {
|
.display-name {
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actor-address {
|
.actor-address {
|
||||||
color: $secondary-text-color;
|
color: $secondary-text-color;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -34,9 +34,19 @@
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<form class="withdraw" v-if="subscriptionConfig !== null">
|
<form class="withdraw" v-if="subscriptionConfig !== null">
|
||||||
|
<h2>Subscribers</h2>
|
||||||
|
<div
|
||||||
|
v-for="subscription in subscribers"
|
||||||
|
class="subscriber"
|
||||||
|
:key="subscription.id"
|
||||||
|
@click="onSubscriberSelected(subscription)"
|
||||||
|
>
|
||||||
|
<profile-list-item :profile="subscription.sender"></profile-list-item>
|
||||||
|
</div>
|
||||||
<input v-model="subscriberAddress" placeholder="Subscriber address">
|
<input v-model="subscriberAddress" placeholder="Subscriber address">
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn"
|
||||||
|
:disabled="!subscriberAddress"
|
||||||
@click.prevent="onCheckSubsciptionState()"
|
@click.prevent="onCheckSubsciptionState()"
|
||||||
>
|
>
|
||||||
Check
|
Check
|
||||||
|
@ -63,17 +73,20 @@ import { Profile, ProfileWrapper } from "@/api/users"
|
||||||
import {
|
import {
|
||||||
configureSubscriptions,
|
configureSubscriptions,
|
||||||
getPricePerSec,
|
getPricePerSec,
|
||||||
|
getSubscribers,
|
||||||
getSubscriptionAuthorization,
|
getSubscriptionAuthorization,
|
||||||
getSubscriptionConfig,
|
getSubscriptionConfig,
|
||||||
getSubscriptionState,
|
getSubscriptionState,
|
||||||
getSubscriptionToken,
|
getSubscriptionToken,
|
||||||
onSubscriptionsEnabled,
|
onSubscriptionsEnabled,
|
||||||
withdrawReceived,
|
withdrawReceived,
|
||||||
|
Subscription,
|
||||||
SubscriptionConfig,
|
SubscriptionConfig,
|
||||||
SubscriptionState,
|
SubscriptionState,
|
||||||
SubscriptionToken,
|
SubscriptionToken,
|
||||||
} from "@/api/subscriptions"
|
} from "@/api/subscriptions"
|
||||||
import Loader from "@/components/Loader.vue"
|
import Loader from "@/components/Loader.vue"
|
||||||
|
import ProfileListItem from "@/components/ProfileListItem.vue"
|
||||||
import { useWallet } from "@/composables/wallet"
|
import { useWallet } from "@/composables/wallet"
|
||||||
import { useInstanceInfo } from "@/store/instance"
|
import { useInstanceInfo } from "@/store/instance"
|
||||||
import { useCurrentUser } from "@/store/user"
|
import { useCurrentUser } from "@/store/user"
|
||||||
|
@ -96,6 +109,7 @@ let subscriptionToken = $ref<SubscriptionToken | null>(null)
|
||||||
let subscriptionsEnabled = $ref<boolean | null>(null)
|
let subscriptionsEnabled = $ref<boolean | null>(null)
|
||||||
let subscriptionConfig = $ref<SubscriptionConfig | null>(null)
|
let subscriptionConfig = $ref<SubscriptionConfig | null>(null)
|
||||||
let subscriptionState = $ref<SubscriptionState | null>(null)
|
let subscriptionState = $ref<SubscriptionState | null>(null)
|
||||||
|
let subscribers = $ref<Subscription[]>([])
|
||||||
let subscriberAddress = $ref<string | null>(null)
|
let subscriberAddress = $ref<string | null>(null)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -161,6 +175,10 @@ async function checkSubscription() {
|
||||||
subscriptionsEnabled = true
|
subscriptionsEnabled = true
|
||||||
// Ensure server is aware of subscription configuration
|
// Ensure server is aware of subscription configuration
|
||||||
await onSubscriptionsEnabled(ensureAuthToken())
|
await onSubscriptionsEnabled(ensureAuthToken())
|
||||||
|
subscribers = await getSubscribers(
|
||||||
|
ensureAuthToken(),
|
||||||
|
profile.id,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
subscriptionsEnabled = false
|
subscriptionsEnabled = false
|
||||||
subscriptionToken = await getSubscriptionToken(
|
subscriptionToken = await getSubscriptionToken(
|
||||||
|
@ -179,7 +197,6 @@ function canEnableSubscriptions(): boolean {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// enableSubscriptions
|
|
||||||
async function onEnableSubscriptions() {
|
async function onEnableSubscriptions() {
|
||||||
if (
|
if (
|
||||||
profileEthereumAddress === null ||
|
profileEthereumAddress === null ||
|
||||||
|
@ -224,6 +241,11 @@ async function onEnableSubscriptions() {
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSubscriberSelected(subscription: Subscription) {
|
||||||
|
subscriberAddress = subscription.sender_address
|
||||||
|
subscriptionState = null
|
||||||
|
}
|
||||||
|
|
||||||
async function onCheckSubsciptionState() {
|
async function onCheckSubsciptionState() {
|
||||||
if (
|
if (
|
||||||
!profileEthereumAddress ||
|
!profileEthereumAddress ||
|
||||||
|
@ -321,6 +343,11 @@ async function onWithdrawReceived() {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $block-inner-padding;
|
gap: $block-inner-padding;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscriber,
|
||||||
input {
|
input {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,10 @@ async function loadNextPage() {
|
||||||
|
|
||||||
.floating-avatar {
|
.floating-avatar {
|
||||||
@include floating-avatar;
|
@include floating-avatar;
|
||||||
|
|
||||||
|
@media screen and (min-width: $screen-breakpoint-medium + 1) {
|
||||||
|
margin-right: -$block-inner-padding / 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-name {
|
.display-name {
|
||||||
|
|
|
@ -174,11 +174,13 @@
|
||||||
@load-next-page="loadNextPage"
|
@load-next-page="loadNextPage"
|
||||||
></post-list>
|
></post-list>
|
||||||
<template v-if="tabName === 'followers' || tabName === 'following'">
|
<template v-if="tabName === 'followers' || tabName === 'following'">
|
||||||
<profile-list-item
|
<router-link
|
||||||
v-for="profile in followList"
|
v-for="profile in followList"
|
||||||
:profile="profile"
|
|
||||||
:key="profile.id"
|
:key="profile.id"
|
||||||
></profile-list-item>
|
:to="{ name: 'profile', params: { profileId: profile.id } }"
|
||||||
|
>
|
||||||
|
<profile-list-item :profile="profile"></profile-list-item>
|
||||||
|
</router-link>
|
||||||
<button
|
<button
|
||||||
v-if="followListNextPageUrl"
|
v-if="followListNextPageUrl"
|
||||||
class="btn secondary next-btn"
|
class="btn secondary next-btn"
|
||||||
|
|
|
@ -9,9 +9,14 @@
|
||||||
<template v-else>No results</template>
|
<template v-else>No results</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isLoading" class="search-result-list">
|
<div v-if="!isLoading" class="search-result-list">
|
||||||
<div class="search-result" v-for="profile in profiles" :key="profile.id">
|
<router-link
|
||||||
|
class="search-result"
|
||||||
|
v-for="profile in profiles"
|
||||||
|
:key="profile.id"
|
||||||
|
:to="{ name: 'profile', params: { profileId: profile.id } }"
|
||||||
|
>
|
||||||
<profile-list-item :profile="profile"></profile-list-item>
|
<profile-list-item :profile="profile"></profile-list-item>
|
||||||
</div>
|
</router-link>
|
||||||
<post
|
<post
|
||||||
v-for="post in posts"
|
v-for="post in posts"
|
||||||
:post="post"
|
:post="post"
|
||||||
|
@ -93,6 +98,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
.search-result {
|
.search-result {
|
||||||
border-bottom: 1px solid $separator-color;
|
border-bottom: 1px solid $separator-color;
|
||||||
|
display: block;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
|
Loading…
Reference in a new issue