Release v1.0.9 - Add wallet tab with Cashu and Lightning support
- Add wallet tab with NWC (Nostr Wallet Connect) Lightning support - Add Cashu ecash wallet with mint management, send/receive tokens - Add Cashu deposit feature (mint via Lightning invoice) - Add token viewer showing proof amounts and timestamps - Add refresh button with auto-refresh for spent proof detection - Add browser sync warning for Cashu users on welcome screen - Add Cashu onboarding info panel with storage considerations - Add settings page sync info note explaining how to change sync - Add backups page for vault snapshot management - Add About section to identity (You) page - Fix lint accessibility issues in wallet component Files modified: - projects/common/src/lib/services/nwc/* (new) - projects/common/src/lib/services/cashu/* (new) - projects/common/src/lib/services/storage/* (extended) - projects/chrome/src/app/components/home/wallet/* - projects/firefox/src/app/components/home/wallet/* - projects/chrome/src/app/components/welcome/* - projects/firefox/src/app/components/welcome/* - projects/chrome/src/app/components/home/settings/* - projects/firefox/src/app/components/home/settings/* - projects/chrome/src/app/components/home/identity/* - projects/firefox/src/app/components/home/identity/* - projects/chrome/src/app/components/home/backups/* (new) - projects/firefox/src/app/components/home/backups/* (new) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import {
|
||||
ConfirmComponent,
|
||||
LoggerService,
|
||||
SignerMetaData_VaultSnapshot,
|
||||
StartupService,
|
||||
StorageService,
|
||||
} from '@common';
|
||||
import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage-service-config';
|
||||
|
||||
@Component({
|
||||
selector: 'app-backups',
|
||||
templateUrl: './backups.component.html',
|
||||
styleUrl: './backups.component.scss',
|
||||
imports: [ConfirmComponent],
|
||||
})
|
||||
export class BackupsComponent implements OnInit {
|
||||
readonly #router = inject(Router);
|
||||
readonly #storage = inject(StorageService);
|
||||
readonly #startup = inject(StartupService);
|
||||
readonly #logger = inject(LoggerService);
|
||||
|
||||
backups: SignerMetaData_VaultSnapshot[] = [];
|
||||
maxBackups = 5;
|
||||
restoringBackupId: string | null = null;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadBackups();
|
||||
this.maxBackups = this.#storage.getSignerMetaHandler().getMaxBackups();
|
||||
}
|
||||
|
||||
loadBackups(): void {
|
||||
this.backups = this.#storage.getSignerMetaHandler().getBackups();
|
||||
}
|
||||
|
||||
async onMaxBackupsChange(event: Event): Promise<void> {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const value = parseInt(input.value, 10);
|
||||
if (!isNaN(value) && value >= 1 && value <= 20) {
|
||||
this.maxBackups = value;
|
||||
await this.#storage.getSignerMetaHandler().setMaxBackups(value);
|
||||
}
|
||||
}
|
||||
|
||||
async createManualBackup(): Promise<void> {
|
||||
const browserSyncData = this.#storage.getBrowserSyncHandler().browserSyncData;
|
||||
if (browserSyncData) {
|
||||
await this.#storage.getSignerMetaHandler().createBackup(browserSyncData, 'manual');
|
||||
this.loadBackups();
|
||||
}
|
||||
}
|
||||
|
||||
async restoreBackup(backupId: string): Promise<void> {
|
||||
this.restoringBackupId = backupId;
|
||||
try {
|
||||
// First, create a pre-restore backup of current state
|
||||
const currentData = this.#storage.getBrowserSyncHandler().browserSyncData;
|
||||
if (currentData) {
|
||||
await this.#storage.getSignerMetaHandler().createBackup(currentData, 'pre-restore');
|
||||
}
|
||||
|
||||
// Get the backup data
|
||||
const backupData = this.#storage.getSignerMetaHandler().getBackupData(backupId);
|
||||
if (!backupData) {
|
||||
throw new Error('Backup not found');
|
||||
}
|
||||
|
||||
// Import the backup
|
||||
await this.#storage.deleteVault(true);
|
||||
await this.#storage.importVault(backupData);
|
||||
this.#logger.logVaultImport('Backup Restore');
|
||||
this.#storage.isInitialized = false;
|
||||
this.#startup.startOver(getNewStorageServiceConfig());
|
||||
} catch (error) {
|
||||
console.error('Failed to restore backup:', error);
|
||||
this.restoringBackupId = null;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteBackup(backupId: string): Promise<void> {
|
||||
await this.#storage.getSignerMetaHandler().deleteBackup(backupId);
|
||||
this.loadBackups();
|
||||
}
|
||||
|
||||
formatDate(isoDate: string): string {
|
||||
const date = new Date(isoDate);
|
||||
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
getReasonLabel(reason?: string): string {
|
||||
switch (reason) {
|
||||
case 'auto':
|
||||
return 'Auto';
|
||||
case 'manual':
|
||||
return 'Manual';
|
||||
case 'pre-restore':
|
||||
return 'Pre-Restore';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
getReasonClass(reason?: string): string {
|
||||
switch (reason) {
|
||||
case 'auto':
|
||||
return 'reason-auto';
|
||||
case 'manual':
|
||||
return 'reason-manual';
|
||||
case 'pre-restore':
|
||||
return 'reason-prerestore';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
goBack(): void {
|
||||
this.#router.navigateByUrl('/home/settings');
|
||||
}
|
||||
|
||||
async onClickLock(): Promise<void> {
|
||||
this.#logger.logVaultLock();
|
||||
await this.#storage.lockVault();
|
||||
this.#router.navigateByUrl('/vault-login');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user