1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-28 17:27:50 +01:00

add credit via paypal

This commit is contained in:
Kyle Spearrin 2019-02-20 17:33:05 -05:00
parent 944187f276
commit 1f6632146b
8 changed files with 199 additions and 9 deletions

View File

@ -90,6 +90,7 @@ import { GroupingsComponent as OrgGroupingsComponent } from './organizations/vau
import { VaultComponent as OrgVaultComponent } from './organizations/vault/vault.component';
import { AccountComponent } from './settings/account.component';
import { AddCreditComponent } from './settings/add-credit.component';
import { AdjustPaymentComponent } from './settings/adjust-payment.component';
import { AdjustStorageComponent } from './settings/adjust-storage.component';
import { ChangeEmailComponent } from './settings/change-email.component';
@ -224,6 +225,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
declarations: [
AcceptOrganizationComponent,
AccountComponent,
AddCreditComponent,
AddEditComponent,
AdjustPaymentComponent,
AdjustSeatsComponent,

View File

@ -0,0 +1,52 @@
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
<div class="card-body">
<h3 class="card-body-header">{{'addCredit' | i18n}}</h3>
<div class="mb-4 text-lg" *ngIf="showOptions">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="Method" id="credit-method-paypal" [value]="paymentMethodType.PayPal" [(ngModel)]="method" (change)="changeMethod()">
<label class="form-check-label" for="credit-method-paypal">
<i class="fa fa-fw fa-paypal"></i> PayPal</label>
</div>
<!--
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="Method" id="credit-method-bitcoin" [value]="paymentMethodType.BitPay" [(ngModel)]="method" (change)="changeMethod()">
<label class="form-check-label" for="credit-method-bitcoin">
<i class="fa fa-fw fa-bitcoin"></i> Bitcoin</label>
</div>
-->
</div>
<div class="row">
<div class="form-group col-4">
<label for="creditAmount">{{'amount' | i18n}}</label>
<div class="input-group mb-3">
<div class="input-group-prepend"><span class="input-group-text">$USD</span></div>
<input id="creditAmount" class="form-control" type="text" name="CreditAmount" [(ngModel)]="creditAmount"
(blur)="formatAmount()" required>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"></i>
<span>{{'submit' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()">
{{'cancel' | i18n}}
</button>
</div>
</form>
<form #ppButtonForm action="{{ppButtonFormAction}}" method="post" target="_top">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="{{ppButtonBusinessId}}">
<input type="hidden" name="button_subtype" value="services">
<input type="hidden" name="no_note" value="1">
<input type="hidden" name="no_shipping" value="1">
<input type="hidden" name="rm" value="1">
<input type="hidden" name="return" value="https://vault.bitwarden.com">
<input type="hidden" name="cancel_return" value="https://vault.bitwarden.com">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynow_LG.gif:NonHosted">
<input type="hidden" name="amount" value="{{creditAmount}}">
<input type="hidden" name="custom" value="{{ppButtonCustomField}}">
<input type="hidden" name="item_name" value="Account Credit">
<input type="hidden" name="item_number" value="{{subject}}">
</form>

View File

@ -0,0 +1,106 @@
import {
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { UserService } from 'jslib/abstractions/user.service';
import { PaymentMethodType } from 'jslib/enums/paymentMethodType';
import { WebConstants } from '../../services/webConstants';
@Component({
selector: 'app-add-credit',
templateUrl: 'add-credit.component.html',
})
export class AddCreditComponent implements OnInit {
@Input() creditAmount = '10.00';
@Input() showOptions = true;
@Input() method = PaymentMethodType.PayPal;
@Input() organizationId: string;
@Output() onAdded = new EventEmitter();
@Output() onCanceled = new EventEmitter();
@ViewChild('ppButtonForm', { read: ElementRef }) ppButtonFormRef: ElementRef;
paymentMethodType = PaymentMethodType;
ppButtonFormAction = WebConstants.paypal.buttonActionProduction;
ppButtonBusinessId = WebConstants.paypal.businessIdProduction;
ppButtonCustomField: string;
subject: string;
formPromise: Promise<any>;
constructor(private userService: UserService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService,
platformUtilsService: PlatformUtilsService) {
if (platformUtilsService.isDev()) {
this.ppButtonFormAction = WebConstants.paypal.buttonActionSandbox;
this.ppButtonBusinessId = WebConstants.paypal.businessIdSandbox;
}
}
async ngOnInit() {
if (this.organizationId != null) {
this.ppButtonCustomField = 'organization_id:' + this.organizationId;
const org = await this.userService.getOrganization(this.organizationId);
if (org != null) {
this.subject = org.name;
}
} else {
const userId = await this.userService.getUserId();
this.subject = await this.userService.getEmail();
this.ppButtonCustomField = 'user_id:' + userId;
}
this.ppButtonCustomField += ',account_credit:true';
}
async submit() {
if (this.creditAmount == null || this.creditAmount === '') {
return;
}
if (this.method === PaymentMethodType.PayPal) {
this.ppButtonFormRef.nativeElement.submit();
return;
}
try {
this.analytics.eventTrack.next({
action: 'Added Credit',
});
this.toasterService.popAsync('success', null, this.i18nService.t('updatedPaymentMethod'));
this.onAdded.emit();
} catch { }
}
changeMethod() {
// TODO:
}
cancel() {
this.onCanceled.emit();
}
formatAmount() {
try {
if (this.creditAmount != null && this.creditAmount !== '') {
const floatAmount = Math.abs(parseFloat(this.creditAmount));
if (floatAmount > 0) {
this.creditAmount = parseFloat((Math.round(floatAmount * 100) / 100).toString())
.toFixed(2).toString();
return;
}
}
} catch { }
this.creditAmount = '';
}
}

View File

@ -8,12 +8,7 @@ import { PaymentMethodType } from 'jslib/enums/paymentMethodType';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
const Keys = {
stripeTest: 'pk_test_KPoCfZXu7mznb9uSCPZ2JpTD',
stripeLive: 'pk_live_bpN0P37nMxrMQkcaHXtAybJk',
btSandbox: 'sandbox_r72q8jq6_9pnxkwm75f87sdc2',
btProduction: 'production_qfbsv8kc_njj2zjtyngtjmbjd',
};
import { WebConstants } from '../../services/webConstants';
const StripeElementStyle = {
base: {
@ -67,8 +62,8 @@ export class PaymentComponent implements OnInit {
this.stripeScript.src = 'https://js.stripe.com/v3/';
this.stripeScript.async = true;
this.stripeScript.onload = () => {
this.stripe = (window as any).Stripe(
this.platformUtilsService.isDev() ? Keys.stripeTest : Keys.stripeLive);
this.stripe = (window as any).Stripe(this.platformUtilsService.isDev() ?
WebConstants.stripeTestKey : WebConstants.stripeLiveKey);
this.stripeElements = this.stripe.elements();
this.setStripeElement();
};
@ -125,7 +120,8 @@ export class PaymentComponent implements OnInit {
if (this.method === 'paypal') {
window.setTimeout(() => {
(window as any).braintree.dropin.create({
authorization: this.platformUtilsService.isDev() ? Keys.btSandbox : Keys.btProduction,
authorization: this.platformUtilsService.isDev() ?
WebConstants.btSandboxKey : WebConstants.btProductionKey,
container: '#bt-dropin-container',
paymentOptionPriority: ['paypal'],
paypal: {

View File

@ -10,6 +10,12 @@
<ng-container *ngIf="billing">
<h2>{{(isCreditBalance ? 'accountCredit' : 'accountBalance') | i18n}}</h2>
<p>{{creditOrBalance | currency:'$'}}</p>
<button type="button" class="btn btn-outline-secondary" (click)="addCredit()" *ngIf="!showAddCredit">
{{'addCredit' | i18n}}
</button>
<app-add-credit [organizationId]="organizationId"
(onAdded)="closeAddCredit(true)" (onCanceled)="closeAddCredit(false)" *ngIf="showAddCredit">
</app-add-credit>
<h2 class="spaced-header">{{'paymentMethod' | i18n}}</h2>
<p *ngIf="!paymentSource">{{'noPaymentMethod' | i18n}}</p>
<ng-container *ngIf="paymentSource">

View File

@ -23,6 +23,7 @@ export class UserBillingComponent implements OnInit {
loading = false;
firstLoaded = false;
showAdjustPayment = false;
showAddCredit = false;
billing: BillingResponse;
paymentMethodType = PaymentMethodType;
transactionType = TransactionType;
@ -70,6 +71,17 @@ export class UserBillingComponent implements OnInit {
} catch { }
}
addCredit() {
this.showAddCredit = true;
}
closeAddCredit(load: boolean) {
this.showAddCredit = false;
if (load) {
this.load();
}
}
changePayment() {
this.showAdjustPayment = true;
}

View File

@ -1502,6 +1502,10 @@
"message": "Add Credit",
"description": "Add more credit to your account's balance."
},
"amount": {
"message": "Amount",
"description": "Dollar amount, or quantity."
},
"goPremium": {
"message": "Go Premium",
"description": "Another way of saying \"Get a premium membership\""

View File

@ -0,0 +1,12 @@
export class WebConstants {
static readonly stripeTestKey = 'pk_test_KPoCfZXu7mznb9uSCPZ2JpTD';
static readonly stripeLiveKey = 'pk_live_bpN0P37nMxrMQkcaHXtAybJk';
static readonly btSandboxKey = 'sandbox_r72q8jq6_9pnxkwm75f87sdc2';
static readonly btProductionKey = 'production_qfbsv8kc_njj2zjtyngtjmbjd';
static readonly paypal = {
businessIdProduction: '4ZDA7DLUUJGMN',
businessIdSandbox: 'AD3LAUZSNVPJY',
buttonActionProduction: 'https://www.paypal.com/cgi-bin/webscr',
buttonActionSandbox: 'https://www.sandbox.paypal.com/cgi-bin/webscr',
};
}