cashu wallet (beta) (testnet)
This commit is contained in:
parent
9a125e3111
commit
985c1494b5
8 changed files with 637 additions and 24 deletions
|
@ -1,8 +1,12 @@
|
|||
import { wallet } from '@/wallet';
|
||||
import { StateController } from '@lit-app/state';
|
||||
import type { NDKUser } from '@nostr-dev-kit/ndk';
|
||||
import formatDateTime from '@utils/formatDateTime';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
|
||||
import { ndk } from '@/ndk';
|
||||
import '@components/MarkdownContent';
|
||||
|
||||
@customElement('arx-forum-post')
|
||||
|
@ -14,6 +18,16 @@ export class ForumPost extends LitElement {
|
|||
@property({ type: String }) content = '';
|
||||
@property({ type: Boolean }) isHighlighted = false;
|
||||
|
||||
@state() private zapAmountDialogOpen = false;
|
||||
@state() public authorProfile: NDKUser | undefined = undefined;
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.authorProfile = ndk.getUser({ pubkey: this.npub });
|
||||
new StateController(this, wallet);
|
||||
wallet.loadWallet();
|
||||
}
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
.post {
|
||||
|
@ -171,14 +185,24 @@ export class ForumPost extends LitElement {
|
|||
}
|
||||
|
||||
private _handleZap() {
|
||||
alert('Zapping is not yet implemented');
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('zap', {
|
||||
detail: { postId: this.id, npub: this.npub },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}),
|
||||
);
|
||||
// setting to false and then to true forces the dialog to open, even when it wasn't closed correctly
|
||||
this.zapAmountDialogOpen = false;
|
||||
setTimeout(() => {
|
||||
this.zapAmountDialogOpen = true;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private async _doZap(e: Event) {
|
||||
if (!(e instanceof CustomEvent)) return;
|
||||
e.preventDefault();
|
||||
const zapAmount = Number.parseInt(e.detail.value);
|
||||
if (Number.isNaN(zapAmount) || zapAmount <= 10) {
|
||||
alert('Zap amount must be greater or equal to 10');
|
||||
return;
|
||||
}
|
||||
await wallet.nutZap(zapAmount, this.authorProfile!, this.id);
|
||||
|
||||
this.zapAmountDialogOpen = false;
|
||||
}
|
||||
|
||||
private _handleDownzap() {
|
||||
|
@ -206,6 +230,16 @@ export class ForumPost extends LitElement {
|
|||
};
|
||||
|
||||
return html`
|
||||
<arx-prompt
|
||||
promptText="Zap amount"
|
||||
placeholder="Enter zap amount"
|
||||
@save=${this._doZap}
|
||||
@cancel=${() => {
|
||||
this.zapAmountDialogOpen = false;
|
||||
}}
|
||||
showInput
|
||||
.open=${this.zapAmountDialogOpen}
|
||||
></arx-prompt>
|
||||
<div class=${classMap(postClasses)} id="post-${this.id}">
|
||||
<div class="post__sidebar">
|
||||
<arx-nostr-profile
|
||||
|
@ -248,7 +282,7 @@ export class ForumPost extends LitElement {
|
|||
></iconify-icon>
|
||||
</arx-button>
|
||||
|
||||
<arx-button label="Zap" @click=${this._handleZap} disabled>
|
||||
<arx-button label="Zap" @click=${this._handleZap}>
|
||||
<iconify-icon
|
||||
slot="prefix"
|
||||
icon="mdi:lightning-bolt"
|
||||
|
|
100
src/components/WalletTransactionLine.ts
Normal file
100
src/components/WalletTransactionLine.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
import { StateController } from '@lit-app/state';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import { type WalletHistory, wallet } from '@/wallet';
|
||||
|
||||
import formatDateTime from '@/utils/formatDateTime';
|
||||
import satsComma from '@/utils/satsComma';
|
||||
import '@components/General/Card';
|
||||
import '@components/General/Input';
|
||||
|
||||
@customElement('arx-wallet-transaction-line')
|
||||
export class WalletTransactionLine extends LitElement {
|
||||
@property({ type: Object }) transaction!: WalletHistory;
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
new StateController(this, wallet);
|
||||
}
|
||||
|
||||
static override styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--color-base-200);
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.transaction {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr auto;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.in {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.out {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.amount {
|
||||
text-align: right;
|
||||
font-family: var(--font-mono);
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.date {
|
||||
color: var(--color-secondary);
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.profiles {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sender {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.recipient {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
@container (max-width: 400px) {
|
||||
.transaction {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.amount {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
override render() {
|
||||
return html`<div class="transaction ${this.transaction.direction}">
|
||||
<span class="amount">
|
||||
${this.transaction.direction === 'in' ? '+' : '-'} ${satsComma(this.transaction.amount)}
|
||||
sats
|
||||
</span>
|
||||
<span class="date">${formatDateTime(this.transaction.created_at * 1000)}</span>
|
||||
<div class="profiles">
|
||||
<arx-nostr-profile
|
||||
pubkey=${this.transaction.senderPubkey}
|
||||
class="sender"
|
||||
></arx-nostr-profile>
|
||||
<arx-nostr-profile
|
||||
pubkey=${this.transaction.recipientPubkey}
|
||||
class="recipient"
|
||||
></arx-nostr-profile>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
82
src/components/Widgets/WalletWidget.ts
Normal file
82
src/components/Widgets/WalletWidget.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import satsComma from '@/utils/satsComma';
|
||||
import { wallet } from '@/wallet';
|
||||
import '@components/General/Fieldset';
|
||||
import '@components/LoadingView';
|
||||
import '@components/WalletTransactionLine';
|
||||
import { StateController } from '@lit-app/state';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
|
||||
@customElement('arx-wallet-widget')
|
||||
export class WalletWidget extends LitElement {
|
||||
@state()
|
||||
public loading = false;
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
new StateController(this, wallet);
|
||||
}
|
||||
|
||||
override async firstUpdated() {
|
||||
this.loading = true;
|
||||
await wallet.loadWallet();
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.widget-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
border-bottom: var(--border) solid var(--color-base-300);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.widget-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
color: var(--color-base-content);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.bitcoin-icon {
|
||||
color: var(--color-warning);
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<div class="widget-header">
|
||||
<h3 class="widget-title">
|
||||
<span class="bitcoin-icon">₿</span> Bitcoin Wallet
|
||||
</h3>
|
||||
</div>
|
||||
<arx-fieldset .legend=${when(
|
||||
this.loading,
|
||||
() => 'Loading...',
|
||||
() => `${satsComma(wallet.balance)} sats`,
|
||||
)}>
|
||||
${when(
|
||||
wallet.sortedHistory.length > 0,
|
||||
() => html`
|
||||
Latest Transaction:
|
||||
<arx-wallet-transaction-line .transaction=${wallet.sortedHistory[0]}></arx-wallet-transaction-line>
|
||||
`,
|
||||
() => 'No transactions yet',
|
||||
)}
|
||||
</arx-fieldset>
|
||||
`;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue