Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,10 @@
<div class="default">No Bitcoin/Nostr content detected.</div>
}
</div>
@if (clipboardItem && !isPaymentClipboardItem(clipboardItem)) {
<div class="verify-container">
<button mat-button color="primary" (click)="onVerify()">Verify with Branta Guardrail</button>
<mat-icon class="icon material-symbols-outlined" color="primary" [matTooltip]="verifyTooltip">info</mat-icon>
</div>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,11 @@
.value {
word-break: break-all;
}

.verify-container {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
padding-top: 10px;
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,60 @@
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { ExpandableTextComponent } from '../../../shared/components/expandable-text/expandable-text.component';
import { ClipboardItem } from '../../../shared/models/clipboard-item';
import { ClipboardItem, PaymentClipboardItem } from '../../../shared/models/clipboard-item';
import { BaseClipboardComponent } from '../base-clipboard';
import { BitcoinAmountComponent } from '../../../shared/components/bitcoin-amount/bitcoin-amount.component';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { lastValueFrom } from 'rxjs';
import { ServerService } from '../../../shared/services/server.service';
import { ToastrService } from 'ngx-toastr';

@Component({
selector: 'app-clipboard-details',
imports: [CommonModule, MatButtonModule, ExpandableTextComponent, BitcoinAmountComponent],
imports: [CommonModule, MatButtonModule, ExpandableTextComponent, BitcoinAmountComponent, MatIconModule, MatTooltipModule],
templateUrl: './clipboard-details.component.html',
styleUrl: './clipboard-details.component.scss'
})
export class ClipboardDetailsComponent extends BaseClipboardComponent {
@Input() clipboardItem: ClipboardItem | null;
@Output() clipboardItemChange = new EventEmitter<ClipboardItem>();

verifyTooltip = "Verify clipboard content against Branta's server.";

constructor(private serverService: ServerService, private toastrService: ToastrService) {
super();
}

onShareFeedback(): void {
window.electron.openUrl('https://branta.pro');
}

onVerify(): void {
(async () => {
var result = await this.queryPayments(this.clipboardItem?.value ?? "")

if (result) {
this.clipboardItemChange.emit(result as PaymentClipboardItem);
} else {
this.toastrService.error(`Payment not found.`);
}
})();
}

private async queryPayments(value: string): Promise<PaymentClipboardItem | null> {
try {
const paymentClipboardItems = await lastValueFrom(this.serverService.getPayment(value));

const paymentClipboardItem = paymentClipboardItems[0];

paymentClipboardItem.name = paymentClipboardItem.platform;
paymentClipboardItem.value = value;

return paymentClipboardItem;
} catch (error) {
return null;
}
}
}
2 changes: 1 addition & 1 deletion src/app/features/clipboard/clipboard.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="container">
<app-clipboard-details [clipboardItem]="clipboardItem"></app-clipboard-details>
<app-clipboard-details [(clipboardItem)]="clipboardItem"></app-clipboard-details>
@if (showHistory) {
<app-clipboard-history [history]="history" [clipboardContent]="clipboardItem?.value"></app-clipboard-history>
}
Expand Down
4 changes: 0 additions & 4 deletions src/app/features/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
<div class="settings">
<div class="section">
<div class="title">General</div>
<div class="option">
<mat-slide-toggle formControlName="checkoutMode">Checkout Mode</mat-slide-toggle>
<mat-icon class="icon material-symbols-outlined" [matTooltip]="checkoutModeTooltip" matTooltipPosition="right">help</mat-icon>
</div>
<div class="option">
<mat-form-field>
<mat-label>Bitcoin Unit</mat-label>
Expand Down
43 changes: 0 additions & 43 deletions src/app/features/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,12 @@ import { SettingsService } from '../../shared/services/settings.service';
export class SettingsComponent {
formGroup: FormGroup;

checkoutModeTooltip = 'Verify addresses by querying Branta with clipboard content. Requires internet.';
developerModeTooltip = "Only check this if you're a developer. Enables staging environment.";

BitcoinUnitTypes = Object.values(BitcoinUnitType);

ClipboardHistoryRolloffTypes = Object.values(ClipboardHistoryRolloffType);

private isCheckoutModeChange = false;

constructor(
private settingsService: SettingsService,
private historyService: HistoryService,
Expand All @@ -40,7 +37,6 @@ export class SettingsComponent {
const settings = settingsService.settings();

this.formGroup = new FormGroup({
checkoutMode: new FormControl(settings.checkoutMode),
bitcoinUnitType: new FormControl(settings.bitcoinUnitType),
generalNotifications: new FormGroup({
bitcoinAddress: new FormControl(settings.generalNotifications.bitcoinAddress),
Expand All @@ -56,19 +52,6 @@ export class SettingsComponent {
developerMode: new FormControl(settings.developerMode)
});

this.formGroup.valueChanges.subscribe((settings) => {
if (!this.isCheckoutModeChange) {
this.settingsService.save(settings);
}

this.isCheckoutModeChange = false;
});

this.formGroup.get('checkoutMode')?.valueChanges.subscribe((value) => {
this.handleCheckoutModeChange(value);
this.clipboardService.rerunGetClipboardItem();
});

this.formGroup.get('developerMode')?.valueChanges.subscribe(() => {
this.clipboardService.rerunGetClipboardItem();
});
Expand All @@ -89,30 +72,4 @@ export class SettingsComponent {
}
});
}

private handleCheckoutModeChange(newValue: boolean): void {
if (!newValue) {
this.settingsService.save(this.formGroup.value);
return;
}

this.isCheckoutModeChange = true;

const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: {
title: 'Turn Checkout Mode on?',
message: 'Are you sure you want to turn Checkout Mode on? This will query Branta with bitcoin addresses you copy.',
submitText: 'Confirm'
}
});

dialogRef.afterClosed().subscribe((confirmed) => {
if (confirmed) {
this.settingsService.save(this.formGroup.value);
this.clipboardService.rerunGetClipboardItem();
} else {
this.formGroup.get('checkoutMode')?.setValue(false, { emitEvent: false });
}
});
}
}
1 change: 0 additions & 1 deletion src/app/shared/models/settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export interface Settings {
checkoutMode: boolean;
developerMode: boolean;
generalNotifications: GeneralNotifications;
clipboardHistory: ClipboardHistory;
Expand Down
37 changes: 0 additions & 37 deletions src/app/shared/services/base-clipboard.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,6 @@ export class BaseClipboardService {
}
// Didn't find the users wallet
else {
if (settings?.checkoutMode) {
const paymentItem = await this.queryPayments(text, serverService);

if (paymentItem) {
if (notify) {
await window.electron.showNotification(paymentItem.platform, paymentItem.description ?? '');
}

return paymentItem;
}
}

if (settings?.generalNotifications.bitcoinAddress && notify) {
await window.electron.showNotification('New Bitcoin Address in Clipboard', 'Bitcoin Address Detected.');
}
Expand Down Expand Up @@ -121,17 +109,6 @@ export class BaseClipboardService {
return null;
}

if (settings?.checkoutMode) {
const paymentItem = await this.queryPayments(text, serverService);

if (paymentItem) {
if (settings?.generalNotifications.lightningAddress && notify) {
await window.electron.showNotification(paymentItem.platform, paymentItem.description ?? '');
}
return paymentItem;
}
}

if (settings?.generalNotifications.lightningAddress && notify) {
await window.electron.showNotification('Lightning Address in Clipboard', 'Lightning Address Detected.');
}
Expand All @@ -145,18 +122,4 @@ export class BaseClipboardService {
return null;
}

private static async queryPayments(value: string, serverService: ServerService): Promise<PaymentClipboardItem | null> {
try {
const paymentClipboardItems = await lastValueFrom(serverService.getPayment(value));

const paymentClipboardItem = paymentClipboardItems[0];

paymentClipboardItem.name = paymentClipboardItem.platform;
paymentClipboardItem.value = value;

return paymentClipboardItem;
} catch (error) {
return null;
}
}
}
35 changes: 3 additions & 32 deletions src/app/shared/services/clipboard.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,32 +142,6 @@ describe('ClipboardService getClipboardItem', () => {
expect(result?.wallet?.name).toBe(vaultName);
});

test.each([
['1HD1cVCJ5ZTgF6Tp7a7F92qqe3945NpKtu', true, true, 1],
['1HD1cVCJ5ZTgF6Tp7a7F92qqe3945NpKtu', false, true, 1],
['1HD1cVCJ5ZTgF6Tp7a7F92qqe3945NpKtu', true, false, 0],
['1HD1cVCJ5ZTgF6Txxxxxxxxxxxxxxxxxxz', true, true, 1]
])('Payment: %s', async (address: string, checkoutMode: boolean, notify: boolean, notificationCount: number) => {
const showNotificationMock = jest.spyOn(window.electron, 'showNotification').mockResolvedValue();

var result = (await BaseClipboardService.getClipboardItem(
address,
notify,
[],
[],
{
checkoutMode,
generalNotifications: {
bitcoinAddress: true
}
} as Settings,
serverServiceMock
)) as PaymentClipboardItem;

expect(showNotificationMock).toHaveBeenCalledTimes(notificationCount);
expect(result?.value).toBe(address);
});

test.each([
[npub, true, true, 1],
[npub, false, true, 0],
Expand Down Expand Up @@ -222,19 +196,17 @@ describe('ClipboardService getClipboardItem', () => {
'lnbc1pwr45dpp5q9wa3sjr4cnyvdh0wwufzldvlnm2qa5lc2sh3qkp3y',
true,
true,
true,
undefined,
0
],
['Lightning address on payment server should show default when checkout is off.', lnbc[0], false, true, true, lnbc[0], 1],
['Lightning address on payment server should show payment when checkout is on.', lnbc[0], true, true, true, lnbc[0], 1],
['Lightning address not on payment server should not show payment when checkout is on.', lnbc[1], true, true, true, lnbc[1], 1]
['Lightning address on payment server should show default when checkout is off.', lnbc[0], true, true, lnbc[0], 1],
['Lightning address on payment server should show payment when checkout is on.', lnbc[0], true, true, lnbc[0], 1],
['Lightning address not on payment server should not show payment when checkout is on.', lnbc[1], true, true, lnbc[1], 1]
])(
'Lightning: %s',
async (
_testDescription: string,
value: string,
checkoutMode: boolean,
notify: boolean,
lightningAddress: boolean,
paymentValue: string | undefined,
Expand All @@ -248,7 +220,6 @@ describe('ClipboardService getClipboardItem', () => {
[],
[],
{
checkoutMode,
generalNotifications: {
lightningAddress
}
Expand Down
1 change: 0 additions & 1 deletion src/app/shared/services/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { BitcoinUnitType, ClipboardHistoryRolloffType, Settings } from '../model
})
export class SettingsService {
defaultSettings: Settings = {
checkoutMode: false,
bitcoinUnitType: BitcoinUnitType.Sats,
developerMode: false,
clipboardHistory: {
Expand Down
Loading