satellite/{web,payments}: show STORJ balance

This change adds a card to the billing overview page, which shows the
user's token balance from coinpayments.

Issue: https://github.com/storj/storj-private/issues/151

Change-Id: I11e295b48791b32b745cb7a11c5b4aad6b56618e
This commit is contained in:
Wilfred Asomani 2023-03-05 18:49:32 +00:00 committed by Storj Robot
parent b98a09fa58
commit b1d4763086
5 changed files with 54 additions and 9 deletions

View File

@ -11,5 +11,11 @@ import (
// Earned by applying of promotional coupon and coins depositing, respectively.
type Balance struct {
FreeCredits int64 `json:"freeCredits"`
Coins decimal.Decimal `json:"coins"`
Coins decimal.Decimal `json:"coins"` // STORJ token balance from storjscan.
Credits decimal.Decimal `json:"credits"`
// Credits is the balance from stripe. This may include the following.
// 1. legacy Coinpayments deposit.
// 2. legacy credit for a manual STORJ deposit.
// 4. bonus manually credited for a storjscan payment once a month before invoicing.
// 5. any other adjustment we may have to make from time to time manually to the customer´s STORJ balance.
}

View File

@ -7,6 +7,7 @@ import (
"context"
"time"
"github.com/shopspring/decimal"
"github.com/stripe/stripe-go/v72"
"github.com/zeebo/errs"
@ -103,8 +104,21 @@ func (accounts *accounts) Balance(ctx context.Context, userID uuid.UUID) (_ paym
return payments.Balance{}, Error.Wrap(err)
}
customerID, err := accounts.service.db.Customers().GetCustomerID(ctx, userID)
if err != nil {
return payments.Balance{}, Error.Wrap(err)
}
customer, err := accounts.service.stripeClient.Customers().Get(customerID, nil)
if err != nil {
return payments.Balance{}, Error.Wrap(err)
}
// customer.Balance is negative if the user has a balance with us.
// https://stripe.com/docs/api/customers/object#customer_object-balance
return payments.Balance{
Coins: balance.AsDecimal(),
Coins: balance.AsDecimal(),
Credits: decimal.NewFromInt(-customer.Balance),
}, nil
}

View File

@ -43,7 +43,7 @@ export class PaymentsHttpApi implements PaymentsApi {
const balance = await response.json();
if (balance) {
return new AccountBalance(balance.freeCredits, balance.coins);
return new AccountBalance(balance.freeCredits, balance.coins, balance.credits);
}
return new AccountBalance();

View File

@ -45,6 +45,12 @@
{{ hasZeroCoins ? "Add Funds" : "See Balance" }}
</p>
</div>
<div v-if="balance.credits" class="total-cost__card">
<AvailableBalanceIcon class="total-cost__card__main-icon" />
<p class="total-cost__card__money-text">${{ balance.credits }}</p>
<p class="total-cost__card__label-text">Legacy STORJ Payments and Bonuses</p>
</div>
</div>
</div>
<div class="cost-by-project">
@ -211,19 +217,26 @@ onMounted(async () => {
}
&__card-container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
margin-top: 20px;
@media screen and (max-width: 786px) {
grid-template-columns: 1fr 1fr;
}
@media screen and (max-width: 425px) {
grid-template-columns: auto;
}
}
&__card {
width: calc(50% - 50px);
min-width: 188px;
overflow: hidden;
box-shadow: 0 0 20px rgb(0 0 0 / 4%);
border-radius: 10px;
background-color: #fff;
padding: 20px;
margin-top: 20px;
display: flex;
flex-direction: column;
justify-content: left;

View File

@ -124,12 +124,24 @@ export interface PaymentsApi {
export class AccountBalance {
constructor(
public freeCredits: number = 0,
// STORJ token balance from storjscan.
private _coins: string = '0',
// STORJ balance from stripe. This may include the following.
// 1. legacy Coinpayments deposit.
// 2. legacy credit for a manual STORJ deposit.
// 4. bonus manually credited for a storjscan payment once a month before invoicing.
// 5. any other adjustment we may have to make from time to time manually to the customer´s STORJ balance.
private _credits: string = '0',
) { }
public get coins(): number {
return parseFloat(this._coins);
}
public get credits(): number {
return parseFloat(this._credits);
}
public get sum(): number {
return this.freeCredits + this.coins;
}