...
 
Commits (2)
......@@ -114,9 +114,7 @@
></minds-admin-monetization>
<minds-admin-programs *ngIf="filter == 'programs'"></minds-admin-programs>
<minds-admin-payouts *ngIf="filter == 'payouts'"></minds-admin-payouts>
<minds-admin-withdrawals
*ngIf="filter == 'withdrawals'"
></minds-admin-withdrawals>
<m-admin-withdrawals *ngIf="filter == 'withdrawals'"></m-admin-withdrawals>
<minds-admin-featured *ngIf="filter == 'featured'"></minds-admin-featured>
<minds-admin-tagcloud *ngIf="filter == 'tagcloud'"></minds-admin-tagcloud>
<m-admin--verify *ngIf="filter == 'verify'"></m-admin--verify>
......
<div class="mdl-grid m-admin-withdrawals" style="max-width: 900px">
<div class="m-admin-withdrawals">
<div class="m-admin-withdrawals__legend">
<ng-container *ngIf="user" i18n>
<b>@{{ user }}</b
>'s withdrawals
</ng-container>
<ng-container *ngIf="!user" i18n>
Pending Withdrawals
</ng-container>
</div>
<div
class="m-admin-withdrawals--user"
*ngIf="user"
i18n="@@M__ADMIN__WITHDRAWALS__USERNAME_TITLE"
class="m-admin-withdrawals__card"
*ngFor="let request of withdrawals; let i = index"
>
<b>@{{ user }}</b
>'s withdrawals
</div>
<ng-container *ngIf="request">
<div class="m-admin-withdrawalsCard__cell">
<div class="m-admin-withdrawalsCardCell__label" i18n>Requested</div>
<table class="mdl-data-table mdl-js-data-table m-border" [mdl]>
<thead>
<tr class="m-admin--withdrawals--ledger-header">
<th
class="mdl-data-table__cell--non-numeric m-data-title"
i18n="@@M__ADMIN__WITHDRAWALS__DATE_COL"
>
Date
</th>
<th
class="mdl-data-table__cell--non-numeric m-data-title"
i18n="Transaction@@M__ADMIN__WITHDRAWALS__TX_COL"
>
Tx
</th>
<th
class="mdl-data-table__cell--non-numeric m-data-title"
i18n="@@M__ADMIN__WITHDRAWALS__AMOUNT_COL"
>
Amount
</th>
<th
class="mdl-data-table__cell--non-numeric m-data-title"
i18n="@@M__ADMIN__WITHDRAWALS__COMPLETED_COL"
>
Completed?
</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let withdrawal of withdrawals; let i = index">
<tr class="m-admin--withdrawals--ledger-row">
<td class="mdl-data-table__cell--non-numeric">
{{ withdrawal.timestamp * 1000 | date: 'short' }}
</td>
<td
class="mdl-data-table__cell--non-numeric m-admin--withdrawals--ledger-tx"
<div class="m-admin-withdrawalsCardCell__body">
{{ request.timestamp * 1000 | date: 'short' }}
</div>
</div>
<div class="m-admin-withdrawalsCard__cell">
<div class="m-admin-withdrawalsCardCell__label" i18n>User</div>
<div class="m-admin-withdrawalsCardCell__body">
<a [routerLink]="['/', request.user?.username]"
>@{{ request.user?.username }}</a
>
{{ withdrawal.tx }}
</td>
<td>{{ withdrawal.amount | token: 18 | number: '1.0-4' }}</td>
<td class="mdl-data-table__cell--non-numeric">
{{ withdrawal.completed ? 'Yes' : 'No' }}
</td>
</tr>
</ng-container>
<tr
class="m-admin--withdrawals--ledger-row m-wire-console--ledger-row-placeholder"
*ngIf="!inProgress && (!withdrawals || !withdrawals.length)"
>
<td
colspan="4"
style="text-align:center"
i18n="@@M__ADMIN__WITHDRAWALS__NO_WITHDRAWALS_NOTE"
</div>
</div>
<div class="m-admin-withdrawalsCard__cell">
<div class="m-admin-withdrawalsCardCell__label" i18n>Signed up</div>
<div class="m-admin-withdrawalsCardCell__body">
{{ request.user?.time_created * 1000 | date: 'shortDate' }}
</div>
</div>
<div class="m-admin-withdrawalsCard__cell">
<div class="m-admin-withdrawalsCardCell__label" i18n>Referrer</div>
<div class="m-admin-withdrawalsCardCell__body">
<ng-container *ngIf="request.referrer; else organicText">
<a [routerLink]="['/', request.referrer.username]"
>@{{ request.referrer.username }}</a
>
</ng-container>
<ng-template #organicText>
<ng-container>(organic)</ng-container>
</ng-template>
</div>
</div>
<div class="m-admin-withdrawalsCard__cell">
<div class="m-admin-withdrawalsCardCell__label" i18n>Amount</div>
<div
class="m-admin-withdrawalsCardCell__body m-admin-withdrawalsCardCell__body--bolder"
>
No withdrawals to show. You can access a user's withdrawal ledger by
using the admin drop-down on their channel.
</td>
</tr>
</tbody>
</table>
{{ request.amount | token: 18 | number: '1.0-4' }}
</div>
</div>
<div class="m-admin-withdrawalsCard__cell">
<div class="m-admin-withdrawalsCardCell__label" i18n>Status</div>
<div class="m-admin-withdrawalsCardCell__body">
{{ request.status?.replace('_', ' ') | uppercase }}
</div>
</div>
<div
class="m-admin-withdrawalsCard__cell m-admin-withdrawalsCard__cell--actions"
*ngIf="request.status === 'pending_approval'"
>
<div class="m-admin-withdrawalsCardCell__body">
<a
[routerLink]="[
'/admin/withdrawals',
{ user: request.user?.username }
]"
>History</a
>
<button
class="mf-button mf-button--smaller"
[disabled]="inProgress"
(click)="approve(request)"
>
Approve
</button>
<button
class="mf-button mf-button--destructive mf-button--smaller"
[disabled]="inProgress"
(click)="reject(request)"
>
Reject
</button>
</div>
</div>
</ng-container>
</div>
<div
class="m-admin-withdrawals__notice"
*ngIf="!inProgress && !withdrawals?.length"
>
No withdrawals to show. You can access a user's ledger by using the admin
drop-down on their channel.
</div>
<infinite-scroll
distance="25%"
(load)="load()"
[moreData]="moreData"
[inProgress]="inProgress"
>
</infinite-scroll>
></infinite-scroll>
</div>
.m-admin-withdrawals {
.mdl-data-table {
width: 100%;
max-width: 900px;
margin: 16px auto 0;
.m-admin-withdrawals__legend {
font-size: 16px;
font-weight: 600;
text-align: center;
margin: 8px 0 16px;
letter-spacing: 1px;
}
.m-admin--withdrawals--ledger-tx {
font-size: 12px;
.m-admin-withdrawals__card {
display: flex;
flex-direction: row;
flex-wrap: wrap;
max-width: 600px;
margin: 0 auto 32px;
padding: 8px;
border: 1px solid;
border-radius: 4px;
@include m-theme() {
background: themed($m-white);
color: themed($m-black);
border-color: themed($m-grey-50);
}
}
.m-admin-withdrawalsCard__cell {
flex-grow: 1;
flex-shrink: 0;
box-sizing: border-box;
min-width: 25%;
padding: 8px;
&--actions {
width: 100%;
text-align: right;
padding-top: 24px;
margin-top: 16px;
border-top: 1px dotted;
@include m-theme() {
border-color: themed($m-grey-50);
}
}
a {
color: inherit;
font: inherit;
text-decoration: none;
border-bottom: 1px dotted;
cursor: pointer;
@include m-theme() {
border-color: themed($m-grey-300);
}
}
.m-admin-withdrawalsCardCell__label {
font-weight: 600;
margin-bottom: 2px;
@include m-theme() {
color: themed($m-grey-300);
}
}
.m-admin-withdrawalsCardCell__body {
&--bolder {
font-weight: bold;
letter-spacing: 0.5px;
}
}
&--actions .m-admin-withdrawalsCardCell__body {
> * {
display: inline-block;
vertical-align: middle;
margin: 0 8px 8px;
}
}
}
.m-admin-withdrawals--user {
width: 100%;
font-size: 14px;
font-weight: 300;
.m-admin-withdrawals__notice {
max-width: 600px;
margin: 32px auto;
padding: 16px;
border: 1px solid;
border-radius: 4px;
text-align: center;
padding: 8px 8px 32px;
@include m-theme() {
background: themed($m-white);
color: themed($m-black);
border-color: themed($m-grey-50);
}
}
}
......@@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router';
@Component({
moduleId: module.id,
selector: 'minds-admin-withdrawals',
selector: 'm-admin-withdrawals',
templateUrl: 'withdrawals.component.html',
})
export class AdminWithdrawals {
......@@ -45,12 +45,19 @@ export class AdminWithdrawals {
this.inProgress = true;
const params = {
limit: 50,
offset: this.offset,
};
if (this.user) {
params['user'] = this.user;
} else {
params['status'] = 'pending_approval';
}
this.client
.get(`api/v2/admin/rewards/withdrawals`, {
limit: 50,
offset: this.offset,
user: this.user,
})
.get(`api/v2/admin/rewards/withdrawals`, params)
.then((response: any) => {
if (!response.withdrawals) {
this.inProgress = false;
......@@ -71,4 +78,58 @@ export class AdminWithdrawals {
this.inProgress = false;
});
}
async approve(withdrawal) {
if (!confirm("Do you want to approve this withdrawal? There's no UNDO.")) {
return;
}
this.inProgress = true;
try {
const endpoint = `api/v2/admin/rewards/withdrawals/${[
withdrawal.user_guid,
withdrawal.timestamp,
withdrawal.tx,
].join('/')}`;
await this.client.put(endpoint);
withdrawal.status = 'approved';
} catch (e) {
alert(
`There was an issue while approving withdrawal: ${(e && e.message) ||
'Unknown server error'}`
);
}
this.inProgress = false;
}
async reject(withdrawal) {
if (!confirm("Do you want to reject this withdrawal? There's no UNDO.")) {
return;
}
this.inProgress = true;
try {
const endpoint = `api/v2/admin/rewards/withdrawals/${[
withdrawal.user_guid,
withdrawal.timestamp,
withdrawal.tx,
].join('/')}`;
await this.client.delete(endpoint);
withdrawal.status = 'rejected';
} catch (e) {
alert(
`There was an issue while rejecting withdrawal: ${(e && e.message) ||
'Unknown server error'}`
);
}
this.inProgress = false;
}
}
......@@ -69,7 +69,7 @@
#withdrawPending
i18n="@@WALLET__TOKENS__WITHDRAW__LEDGER__PENDING_LABEL"
>
PENDING
{{ withdrawal.status.replace('_', ' ') | uppercase }}
</ng-template>
<div class="mdl-layout-spacer"></div>
......
......@@ -8,20 +8,23 @@
class="m-border mdl-color--white m-token-withdraw"
*ngIf="session.getLoggedInUser().rewards"
>
<p>
<ng-container i18n="@@WALLET__TOKENS__WITHDRAW__REQUEST_DESC">
You can request to withdraw your token rewards to your 'onchain' wallet
below. Note: a small amount of ETH will be charged to cover the
transaction fee. Withdrawals may take a few hours to complete.
</ng-container>
<ng-container
*ngIf="withholding"
i18n="@@WALLET__TOKENS__WITHDRAW__REQUEST_UNAVAILABLE_DESC"
>
{{ withholding | number }} tokens are unavailable due to credit card
payment. They will be released after 30 days the payment occurred.
</ng-container>
<p i18n>
You can request to withdraw up to {available, plural, =1
{{{available | number}} token} other {{{available | number}} tokens}} from
your rewards to your <b>OnChain</b> wallet below.
</p>
<p *ngIf="withholding" i18n>
{withholding, plural, =1
{{{withholding | number}} token} other {{{withholding | number}} tokens}}
are unavailable due to credit card payment. They will be released after 30
days the payment occurred.
</p>
<p class="m-token-withdraw__note" i18n>
Note: a small amount of ETH will be charged to cover the transaction fee.
Withdrawals <b>go through an approval process</b>
and may take up to 72 hours to complete.
</p>
<div class="m-token-withdraw--form">
......
......@@ -2,9 +2,18 @@
margin-bottom: $minds-padding;
padding: $minds-padding * 2;
> p {
margin-bottom: 8px;
&.m-token-withdraw__note {
font-size: 12px;
opacity: 0.7;
}
}
.m-token-withdraw--form {
display: flex;
margin-bottom: $minds-padding;
margin: 16px 0 8px;
.m-token-withdraw--input,
.m-token-withdraw--submit-button {
......