mirror of
https://github.com/bitwarden/web
synced 2025-12-15 07:43:16 +00:00
add credit via paypal
This commit is contained in:
@@ -90,6 +90,7 @@ import { GroupingsComponent as OrgGroupingsComponent } from './organizations/vau
|
|||||||
import { VaultComponent as OrgVaultComponent } from './organizations/vault/vault.component';
|
import { VaultComponent as OrgVaultComponent } from './organizations/vault/vault.component';
|
||||||
|
|
||||||
import { AccountComponent } from './settings/account.component';
|
import { AccountComponent } from './settings/account.component';
|
||||||
|
import { AddCreditComponent } from './settings/add-credit.component';
|
||||||
import { AdjustPaymentComponent } from './settings/adjust-payment.component';
|
import { AdjustPaymentComponent } from './settings/adjust-payment.component';
|
||||||
import { AdjustStorageComponent } from './settings/adjust-storage.component';
|
import { AdjustStorageComponent } from './settings/adjust-storage.component';
|
||||||
import { ChangeEmailComponent } from './settings/change-email.component';
|
import { ChangeEmailComponent } from './settings/change-email.component';
|
||||||
@@ -224,6 +225,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||||||
declarations: [
|
declarations: [
|
||||||
AcceptOrganizationComponent,
|
AcceptOrganizationComponent,
|
||||||
AccountComponent,
|
AccountComponent,
|
||||||
|
AddCreditComponent,
|
||||||
AddEditComponent,
|
AddEditComponent,
|
||||||
AdjustPaymentComponent,
|
AdjustPaymentComponent,
|
||||||
AdjustSeatsComponent,
|
AdjustSeatsComponent,
|
||||||
|
|||||||
52
src/app/settings/add-credit.component.html
Normal file
52
src/app/settings/add-credit.component.html
Normal 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>
|
||||||
106
src/app/settings/add-credit.component.ts
Normal file
106
src/app/settings/add-credit.component.ts
Normal 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 = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,12 +8,7 @@ import { PaymentMethodType } from 'jslib/enums/paymentMethodType';
|
|||||||
|
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
|
||||||
const Keys = {
|
import { WebConstants } from '../../services/webConstants';
|
||||||
stripeTest: 'pk_test_KPoCfZXu7mznb9uSCPZ2JpTD',
|
|
||||||
stripeLive: 'pk_live_bpN0P37nMxrMQkcaHXtAybJk',
|
|
||||||
btSandbox: 'sandbox_r72q8jq6_9pnxkwm75f87sdc2',
|
|
||||||
btProduction: 'production_qfbsv8kc_njj2zjtyngtjmbjd',
|
|
||||||
};
|
|
||||||
|
|
||||||
const StripeElementStyle = {
|
const StripeElementStyle = {
|
||||||
base: {
|
base: {
|
||||||
@@ -67,8 +62,8 @@ export class PaymentComponent implements OnInit {
|
|||||||
this.stripeScript.src = 'https://js.stripe.com/v3/';
|
this.stripeScript.src = 'https://js.stripe.com/v3/';
|
||||||
this.stripeScript.async = true;
|
this.stripeScript.async = true;
|
||||||
this.stripeScript.onload = () => {
|
this.stripeScript.onload = () => {
|
||||||
this.stripe = (window as any).Stripe(
|
this.stripe = (window as any).Stripe(this.platformUtilsService.isDev() ?
|
||||||
this.platformUtilsService.isDev() ? Keys.stripeTest : Keys.stripeLive);
|
WebConstants.stripeTestKey : WebConstants.stripeLiveKey);
|
||||||
this.stripeElements = this.stripe.elements();
|
this.stripeElements = this.stripe.elements();
|
||||||
this.setStripeElement();
|
this.setStripeElement();
|
||||||
};
|
};
|
||||||
@@ -125,7 +120,8 @@ export class PaymentComponent implements OnInit {
|
|||||||
if (this.method === 'paypal') {
|
if (this.method === 'paypal') {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
(window as any).braintree.dropin.create({
|
(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',
|
container: '#bt-dropin-container',
|
||||||
paymentOptionPriority: ['paypal'],
|
paymentOptionPriority: ['paypal'],
|
||||||
paypal: {
|
paypal: {
|
||||||
|
|||||||
@@ -10,6 +10,12 @@
|
|||||||
<ng-container *ngIf="billing">
|
<ng-container *ngIf="billing">
|
||||||
<h2>{{(isCreditBalance ? 'accountCredit' : 'accountBalance') | i18n}}</h2>
|
<h2>{{(isCreditBalance ? 'accountCredit' : 'accountBalance') | i18n}}</h2>
|
||||||
<p>{{creditOrBalance | currency:'$'}}</p>
|
<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>
|
<h2 class="spaced-header">{{'paymentMethod' | i18n}}</h2>
|
||||||
<p *ngIf="!paymentSource">{{'noPaymentMethod' | i18n}}</p>
|
<p *ngIf="!paymentSource">{{'noPaymentMethod' | i18n}}</p>
|
||||||
<ng-container *ngIf="paymentSource">
|
<ng-container *ngIf="paymentSource">
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export class UserBillingComponent implements OnInit {
|
|||||||
loading = false;
|
loading = false;
|
||||||
firstLoaded = false;
|
firstLoaded = false;
|
||||||
showAdjustPayment = false;
|
showAdjustPayment = false;
|
||||||
|
showAddCredit = false;
|
||||||
billing: BillingResponse;
|
billing: BillingResponse;
|
||||||
paymentMethodType = PaymentMethodType;
|
paymentMethodType = PaymentMethodType;
|
||||||
transactionType = TransactionType;
|
transactionType = TransactionType;
|
||||||
@@ -70,6 +71,17 @@ export class UserBillingComponent implements OnInit {
|
|||||||
} catch { }
|
} catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addCredit() {
|
||||||
|
this.showAddCredit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAddCredit(load: boolean) {
|
||||||
|
this.showAddCredit = false;
|
||||||
|
if (load) {
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changePayment() {
|
changePayment() {
|
||||||
this.showAdjustPayment = true;
|
this.showAdjustPayment = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1502,6 +1502,10 @@
|
|||||||
"message": "Add Credit",
|
"message": "Add Credit",
|
||||||
"description": "Add more credit to your account's balance."
|
"description": "Add more credit to your account's balance."
|
||||||
},
|
},
|
||||||
|
"amount": {
|
||||||
|
"message": "Amount",
|
||||||
|
"description": "Dollar amount, or quantity."
|
||||||
|
},
|
||||||
"goPremium": {
|
"goPremium": {
|
||||||
"message": "Go Premium",
|
"message": "Go Premium",
|
||||||
"description": "Another way of saying \"Get a premium membership\""
|
"description": "Another way of saying \"Get a premium membership\""
|
||||||
|
|||||||
12
src/services/webConstants.ts
Normal file
12
src/services/webConstants.ts
Normal 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',
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user